[NUI.Physics2D] Add binding for Chipmunk2D physics engine
[platform/core/csapi/tizenfx.git] / test / Tizen.NUI.Physics2D.Sample / Physics2DSample.cs
1 /*
2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 using System;
19 using System.Runtime.InteropServices;
20 using System.Runtime.CompilerServices;
21 using System.Text;
22 using System.Linq;
23 using Tizen.NUI.Physics2D.Chipmunk;
24
25 // Tests the basic functionality of the Chipmunk2D physics engine without the need of any rendering.
26 // It sets up a 2D physics simulation with a dynamic circle dropping to the top of two static segments
27 // representing the ground and bouncing back. The simulation is run for a fixed number of time steps,
28 // and the position of the circle body is printed at each step to verify the correctness of the physics
29 // simulation.
30
31 class Physics2DSample
32 {
33     public Physics2DSample()
34     {
35         // Create a space for physics simulation
36         var space = new Space();
37     
38         // Set up gravity along the Y-axis (negative value for downward)
39         var gravity = new Vect(0, -100);
40         space.Gravity = gravity;
41         
42         // Create two static bodies (static bodies do not move) with shapes (segments) to form the ground
43         var groundBody1 = new Body(BodyType.Static);
44         var groundBody2 = new Body(BodyType.Static);
45                     
46         // Add the body to the space
47         space.AddBody(groundBody1);
48         space.AddBody(groundBody2);
49
50         var groundStart = new Vect(-1000, 0); // Start point of the ground
51         var groundEnd = new Vect(1000, 0); // End point of the ground
52     
53         var groundShape1 = new Segment(groundBody1, groundStart, groundEnd, 0);
54         var groundShape2 = new Segment(groundBody2, groundStart, groundEnd, 0);
55         
56         groundShape1.CollisionType = 0;
57         groundShape2.CollisionType = 1;
58         
59         groundShape1.Elasticity = 0.85f;
60         groundShape2.Elasticity = 0.85f;
61     
62         // Add the shapes to the space
63         space.AddShape(groundShape1);
64         space.AddShape(groundShape2);
65     
66         // Create a dynamic body with a circle shape
67         var radius = 20.0;
68         var mass = 1.0;
69         var moment = Circle.MomentForCircle(mass, 0, radius, Vect.Zero);
70         
71         // Set initial position for the circle
72         var circleBody = new Body(mass, moment);
73         circleBody.Position = new Vect(0, 50);
74     
75         // Add the body to the space
76         space.AddBody(circleBody);
77     
78         // Create a circle shape
79         var circleShape = new Circle(circleBody, radius, Vect.Zero);
80         circleShape.CollisionType = 2;
81         circleShape.Elasticity = 0.85f;
82     
83         // Add the circle shape to the space
84         space.AddShape(circleShape);
85
86         // Detect the collision between the circle and the ground        
87         CollisionHandler handler = space.GetOrCreateCollisionHandler(0, 2);
88         handler.Data = new StringBuilder();
89         
90         handler.Begin = (arbiterHandle, spaceHandle, userData) =>
91         {
92             StringBuilder builder = (StringBuilder)userData;
93             _ = builder.Append("Begin -> ");
94             
95             Console.WriteLine("CollisionHandler::" + handler.Data.ToString());
96         };
97     
98         handler.PreSolve = (arbiterHandle, spaceHandle, userData) =>
99         {
100             StringBuilder builder = (StringBuilder)userData;
101             _ = builder.Append("PreSolve -> ");
102             
103             Console.WriteLine("CollisionHandler::" + handler.Data.ToString());
104     
105             return true;
106         };
107     
108         handler.PostSolve = (arbiterHandle, spaceHandle, userData) =>
109         {
110             StringBuilder builder = (StringBuilder)userData;
111             _ = builder.Append("PostSolve -> ");
112             
113             Console.WriteLine("CollisionHandler::" + handler.Data.ToString());
114         };
115     
116         handler.Separate = (arbiterHandle, spaceHandle, userData) =>
117         {
118             StringBuilder builder = (StringBuilder)userData;
119             _ = builder.Append("Separate -> ");
120             
121             Console.WriteLine("CollisionHandler::" + handler.Data.ToString());
122         };
123         
124     
125         // Simulate the physics for some time steps
126         var numSteps = 60; // Number of simulation steps
127         var timeStep = 1.0 / 60.0; // Time step for each simulation step (60 FPS)
128         
129         // Set the velocity of the circle body to make it move to the right
130         circleBody.Velocity = new Vect(100, 0); // Velocity of (100, 0) along the X-axis
131         
132         for (int i = 0; i < numSteps; ++i)
133         {
134             space.Step(timeStep);
135     
136             // Print the position of the circle body during simulation
137             var position = circleBody.Position;
138             Console.WriteLine("Step " + i + " - Circle Position: (" + position.X + ", " + position.Y + ")");
139         }
140
141         // Make a point query on a shape
142         {
143             circleShape.Filter = new ShapeFilter((UIntPtr)10, 1, 5);
144             ShapeFilter filter = circleShape.Filter;
145             Console.WriteLine("ShapeFilter: " + filter.Group + ", " + filter.Categories + ", " + filter.Mask);
146         
147             var body = new Body(1, 1.66);
148             var shape = new Box(body, 2, 2, 0);
149     
150             PointQueryInfo point = shape.PointQuery(new Vect(3, 4));
151             Console.WriteLine("Shape PointQuery: Distance: " + point.Distance + ", Point: " + point.Point + ", Gradient.X: " + point.Gradient.X + ", Gradient.Y: " + point.Gradient.Y);            
152     
153             shape.Dispose();
154             body.Dispose();
155         }
156     
157         // Make a point query on a space
158         {
159             var mySpace = new Space();
160             var body = new Body(1, 1.66);
161             var shape = new Box(body, 100, 100, 0);
162     
163             body.Position = new Vect(0, 0);
164     
165             PointQueryInfo[] infos = mySpace.PointQuery(body.Position, 10.0, ShapeFilter.FILTER_ALL).ToArray();
166             Console.WriteLine("Space PointQuery: infos.Length: " + infos.Length);
167     
168             mySpace.AddBody(body);
169             mySpace.AddShape(shape);
170     
171             infos = mySpace.PointQuery(body.Position, 10.0, ShapeFilter.FILTER_ALL).ToArray();
172             Console.WriteLine("Space PointQuery: infos.Length: " + infos.Length);
173     
174             if (infos.Length > 0 && shape == infos[0].Shape)
175             {
176                 Console.WriteLine("Space PointQuery: The shape matches");
177             }
178     
179             PointQueryInfo info = space.PointQueryNearest(new Vect(0, 0), 100.0, ShapeFilter.FILTER_ALL);
180             
181             if (info == null || info.Shape == null)
182             {
183                 Console.WriteLine("Space PointQueryNearest: No shape is found");
184             }
185             else
186             {
187                 Console.WriteLine("Shape PointQueryNearest: Distance: " + info.Distance + ", Point: " + info.Point + ", Gradient.X: "  + info.Gradient.X + ", Gradient.Y: " + info.Gradient.Y + ", Body position: " + info.Shape.Body.Position);
188             }
189     
190             shape.Dispose();
191             body.Dispose();
192             mySpace.Dispose();
193         }
194         
195         // Clean up
196         groundShape1.Dispose();
197         groundShape2.Dispose();
198         circleShape.Dispose();
199     
200         groundBody1.Dispose();
201         groundBody2.Dispose();
202         circleBody.Dispose();
203     
204         space.Dispose();
205     }
206     
207     /// <summary>
208     /// The main entry point for the application.
209     /// </summary>
210     [STAThread] // Forces app to use one thread to access NUI
211     static void Main(string[] args)
212     {
213         Physics2DSample example = new Physics2DSample();
214     }
215 }
216