From 66dd5cff75c6ef86710df2bb691b81f6ccc9a0c1 Mon Sep 17 00:00:00 2001 From: Tim Ofenbach Date: Wed, 25 Apr 2018 22:57:22 +0200 Subject: [PATCH 01/46] Update README.md --- README.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 5759a81..1e7fb3d 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,4 @@ -# catengine -Easy to use 2D Framework for Android. - -# use cases -- creating simple 2D games - - animations/movements - - particle - - different screens (intro, menu, game, options etc) -- creating simple apps with animations, movements etc. - -# contact -Questions? Email me: tim@ofenba.ch +# new features ++ independent positions ++ particle class ++ gravity function From 57433663cce2d64022f36291fa0920d06906512d Mon Sep 17 00:00:00 2001 From: Tim Ofenbach Date: Wed, 25 Apr 2018 22:57:49 +0200 Subject: [PATCH 02/46] Delete .gitignore --- .gitignore | 55 ------------------------------------------------------ 1 file changed, 55 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 520a863..0000000 --- a/.gitignore +++ /dev/null @@ -1,55 +0,0 @@ -# Built application files -*.apk -*.ap_ - -# Files for the ART/Dalvik VM -*.dex - -# Java class files -*.class - -# Generated files -bin/ -gen/ -out/ - -# Gradle files -.gradle/ -build/ - -# Local configuration file (sdk path, etc) -local.properties - -# Proguard folder generated by Eclipse -proguard/ - -# Log Files -*.log - -# Android Studio Navigation editor temp files -.navigation/ - -# Android Studio captures folder -captures/ - -# Intellij -*.iml -.idea/workspace.xml -.idea/tasks.xml -.idea/gradle.xml -.idea/dictionaries -.idea/libraries - -# Keystore files -*.jks - -# External native build folder generated in Android Studio 2.2 and later -.externalNativeBuild - -# Google Services (e.g. APIs or Firebase) -google-services.json - -# Freeline -freeline.py -freeline/ -freeline_project_description.json From c8e5d28293c069d77aa753b2d347611568dfd641 Mon Sep 17 00:00:00 2001 From: Tim Ofenbach Date: Wed, 25 Apr 2018 23:02:27 +0200 Subject: [PATCH 03/46] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e7fb3d..0de65f6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # new features -+ independent positions +̶+ i̶̶n̶̶d̶̶e̶̶p̶̶e̶̶n̶̶d̶̶e̶̶n̶̶t̶̶ ̶̶p̶̶o̶̶s̶̶i̶̶t̶̶i̶̶o̶̶n̶̶s̶ + particle class + gravity function From 7bb2854e10e8a8e8040dcfeb833accb6396a500a Mon Sep 17 00:00:00 2001 From: Tim Ofenbach Date: Wed, 25 Apr 2018 23:02:43 +0200 Subject: [PATCH 04/46] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0de65f6..71fa83a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # new features -̶+ i̶̶n̶̶d̶̶e̶̶p̶̶e̶̶n̶̶d̶̶e̶̶n̶̶t̶̶ ̶̶p̶̶o̶̶s̶̶i̶̶t̶̶i̶̶o̶̶n̶̶s̶ ++ ̶i̶̶n̶̶d̶̶e̶̶p̶̶e̶̶n̶̶d̶̶e̶̶n̶̶t̶̶ ̶̶p̶̶o̶̶s̶̶i̶̶t̶̶i̶̶o̶̶n̶̶s̶ + particle class + gravity function From 07d01c92bb9ff2cca6dfe9f22aab8efd9bc5ec32 Mon Sep 17 00:00:00 2001 From: Tim Ofenbach Date: Wed, 25 Apr 2018 23:07:54 +0200 Subject: [PATCH 05/46] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71fa83a..3611af3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # new features + ̶i̶̶n̶̶d̶̶e̶̶p̶̶e̶̶n̶̶d̶̶e̶̶n̶̶t̶̶ ̶̶p̶̶o̶̶s̶̶i̶̶t̶̶i̶̶o̶̶n̶̶s̶ + particle class -+ gravity function ++ ̶g̶̶r̶̶a̶̶v̶̶i̶̶t̶̶y̶̶ ̶̶f̶̶u̶̶n̶̶c̶̶t̶̶i̶̶o̶̶n̶ From 2c97ccaafb0d426eab3dec33170a6e7cb7da66da Mon Sep 17 00:00:00 2001 From: Tim Ofenbach Date: Wed, 25 Apr 2018 23:16:41 +0200 Subject: [PATCH 06/46] Add files via upload added relative positions added gravity function added particle/sprite superclass (w.i.p.) --- framework/Button.java | 27 ++++ framework/CollisionDetection.java | 67 ++++++++ framework/Image.java | 250 ++++++++++++++++++++++++++++++ framework/Music.java | 79 ++++++++++ framework/Sound.java | 44 ++++++ gamestuff/Particle.java | 30 ++++ main/Camera.java | 16 ++ main/MainActivity.java | 33 ++++ main/MainView.java | 56 +++++++ main/Screen.java | 25 +++ main/Settings.java | 33 ++++ main/TouchEvent.java | 21 +++ 12 files changed, 681 insertions(+) create mode 100644 framework/Button.java create mode 100644 framework/CollisionDetection.java create mode 100644 framework/Image.java create mode 100644 framework/Music.java create mode 100644 framework/Sound.java create mode 100644 gamestuff/Particle.java create mode 100644 main/Camera.java create mode 100644 main/MainActivity.java create mode 100644 main/MainView.java create mode 100644 main/Screen.java create mode 100644 main/Settings.java create mode 100644 main/TouchEvent.java diff --git a/framework/Button.java b/framework/Button.java new file mode 100644 index 0000000..66ab4a3 --- /dev/null +++ b/framework/Button.java @@ -0,0 +1,27 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import ofenbach.exampleapp.main.TouchEvent; // change this to your package name + +/* Same as Image.java but can register touch */ +/* @creation: March 2014 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class Button extends Image { + + public Button(int path) { + super(path); + } + + public boolean isPressed() { + + // Touch coords + int touchX = TouchEvent.getX(); + int touchY = TouchEvent.getY(); + + // Hitbox check + return (touchX > super.getX() && touchX < super.getX() + super.getWidth() && touchY > super.getY() && touchY < super.getY() + super.getHeight()); + + } + +} diff --git a/framework/CollisionDetection.java b/framework/CollisionDetection.java new file mode 100644 index 0000000..b74d1e3 --- /dev/null +++ b/framework/CollisionDetection.java @@ -0,0 +1,67 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Rect; + +/* used by Image.java to detect collision between two images. */ +/* @creation: September 2016 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class CollisionDetection { + + /** + * @param bitmap1 First bitmap + * @param x1 x-position of bitmap1 on screen. + * @param y1 y-position of bitmap1 on screen. + * @param bitmap2 second bitmap + * @param x2 x-position of bitmap2 on screen. + * @param y2 y-position of bitmap2 on screen. + */ + + public static boolean isCollisionDetected(Bitmap bitmap1, int x1, int y1, Bitmap bitmap2, int x2, int y2) { + + Rect bounds1 = new Rect(x1, y1, x1+bitmap1.getWidth(), y1+bitmap1.getHeight()); + Rect bounds2 = new Rect(x2, y2, x2+bitmap2.getWidth(), y2+bitmap2.getHeight()); + + if (Rect.intersects(bounds1, bounds2)) { + Rect collisionBounds = getCollisionBounds(bounds1, bounds2); + + for (int i = collisionBounds.left; i < collisionBounds.right; i++) { + + for (int j = collisionBounds.top; j < collisionBounds.bottom; j++) { + + int bitmap1Pixel = bitmap1.getPixel(i-x1, j-y1); + int bitmap2Pixel = bitmap2.getPixel(i-x2, j-y2); + + if (isFilled(bitmap1Pixel) && isFilled(bitmap2Pixel)) { + return true; + } + + } + + } + + } + + return false; + + } + + private static Rect getCollisionBounds(Rect rect1, Rect rect2) { + + int left = (int) Math.max(rect1.left, rect2.left); + int top = (int) Math.max(rect1.top, rect2.top); + int right = (int) Math.min(rect1.right, rect2.right); + int bottom = (int) Math.min(rect1.bottom, rect2.bottom); + + return new Rect(left, top, right, bottom); + + } + + private static boolean isFilled(int pixel) { + return pixel != Color.TRANSPARENT; + } + +} diff --git a/framework/Image.java b/framework/Image.java new file mode 100644 index 0000000..7480e37 --- /dev/null +++ b/framework/Image.java @@ -0,0 +1,250 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.graphics.Paint; + +import ofenbach.exampleapp.main.MainView; // change this to your package name +import ofenbach.exampleapp.main.Settings; // change this to your package name + +/* able to display .png pictures */ +/* @creation: February 2014 */ +/* @update: 26.4.2018 */ +/* @new: relative positions */ +/* @author: Tim B. Ofenbach */ + + +public class Image { + + // Bitmap & Path + Bitmap bitmap; + int path; + + // Position & Angle + public double x = 0; // width: 1920 + public double y = 0; // height: 1080 + int angle; + + // Matrix & Paint + Matrix m; + Paint p; + + // Gravity + double gravity_factor; + double gravity_timer; + + + /* CONSTRUCTOR */ + public Image(int path) { + + // Parameter + this.path = path; + + // Erzeugung + m = new Matrix(); + p = new Paint(); + + // Bitmap Creation + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inScaled = false; + bitmap = BitmapFactory.decodeResource(Settings.context.getResources(), path, options); + + } + + + /* DRAW */ + public void draw() { + + // Anglesettings + m.reset(); + m.postRotate(angle, bitmap.getWidth() / 2, bitmap.getHeight() / 2); + m.postTranslate((float) ((x/1920)*Settings.getScreenWidth), (float) ((y/1080)*Settings.getScreenHeight)); + + // Draw + MainView.global_canvas.drawBitmap(bitmap, m, p); + + } + + + /* SCALING */ + public void scale(double factor) { + + // Calculation + double relativewidth = 1080 / (factor * bitmap.getWidth()); + double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); + double width = Settings.getScreenWidth() / relativewidth; + double height = ratio * width; + + // Scaling + bitmap = Bitmap.createScaledBitmap(bitmap, (int) width, (int) height, false); + + } + public void scaleFullscreen() { + bitmap = Bitmap.createScaledBitmap(bitmap, Settings.getScreenWidth(), Settings.getScreenHeight(), false); + } + public void scale() { + + /* SCALING FOR SCRATCH */ + + // Calculation + double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); + double realwidth = Settings.getScreenWidth() * ((double) bitmap.getWidth()*2 / 480); + double realheight = realwidth * ratio;; + + // Scaling + bitmap = Bitmap.createScaledBitmap(bitmap, (int) realwidth, (int) realheight, false); + + } + public void scaleHalf() { + // fuer bilder die doppelt so gross sind (halbe pixel) + double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); + double realwidth = Settings.getScreenWidth() * ((double) bitmap.getWidth() / 480); + double realheight = realwidth * ratio;; + + // Scaling + bitmap = Bitmap.createScaledBitmap(bitmap, (int) realwidth, (int) realheight, false); + } + + + /* SET FUNCTIONS */ + public void setAlpha(int alpha) { + p.setAlpha(alpha); + } + public void move(double distance) { + + // Calculation + double distanceX = distance * Math.sin(angle); + double distanceY = distance * Math.cos(angle); + + // Update X Y + x += distanceX; + y += distanceY; + + } + public void goTo(int xPos, int yPos) { + x = xPos; + y = yPos; + } + public void setX(double xPos) { + this.x = xPos; + } + public void setXtoMiddle() { + this.x = Settings.getScreenWidth() / 2 - this.getWidth() / 2; + } + public void setY(double yPos) { + this.y = yPos; + } + public void setYtoMiddle() { + this.y = Settings.getScreenHeight() / 2 - this.getHeight() / 2; + } + public void setRotation(double angle) { + this.angle = (int) angle; + m.reset(); + m.postRotate((int) angle, bitmap.getWidth() / 2, bitmap.getHeight() / 2); + m.postTranslate((int) x, (int) y); + } + + + /* GET FUNCTIONS */ + public double getX() { + return x; + } + public double getY() { + return y; + } + public int getWidth() { + return bitmap.getWidth(); + } + public int getHeight() { + return bitmap.getHeight(); + } + public int getAngle() { + return angle; + } + public int getAlpha() { + return p.getAlpha(); + } + public Bitmap getBitMap() { + return bitmap; + } + + + /* COLLISION */ + public boolean collidesWith(Image image) { + + // See CollisionDetection.java + return CollisionDetection.isCollisionDetected(bitmap, (int) x, (int) y, image.bitmap, (int) image.x, (int) image.y); + + } + + /* GRAVITY */ + public void setGravity(double factor) { // e.g. factor=9.81, factor = 0 -> false, factor != 0 -> true + this.gravity_factor = factor; + } + public void applyGravity() { // updates gravity movement (put this in your repeat() + this.y += gravity_timer*gravity_factor; + this.gravity_timer ++; + } + + + /* ON SCREEN? */ + public boolean isInScreen() { + if (this.x > -this.getWidth() && this.x < Settings.getScreenWidth()) { + if (this.y > -this.getHeight() && this.y < Settings.getScreenHeight()) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + + // Extra Stuff + public double getAngleTo(Image image) { + + // Vars + double delta_x; + double delta_y; + double hypo; // Pythagoras + double angle = 0; + + // ∆-X + if (image.x > this.x) { + delta_x = image.x - this.x; + } else { + delta_x = this.x - image.x; + } + + // ∆Y + // Wenn Image unter diesem Image + if (image.y > this.y) { + delta_y = image.y - this.y; + } else { // Wenn Image ueber diesem Image + delta_y = this.y - image.y; + } + + // Satz des Pythagoras a^2 + b^2 = c^2 + // <=> sin(alpha) = Gegenkathete (∆x) / Hypothenuse (Wurzel aus (∆x^2 + ∆y^2)) + // <=> alpha = arcsin(∆x / (sqrt(∆x^2+∆y^2) + hypo = Math.sqrt(delta_x*delta_x + delta_y*delta_y); + angle = Math.asin( delta_y / hypo ); // alpha = arcsin(gegenkathete / hypo) + angle = Math.toDegrees(angle); + + // Umkehrung des Winkels wenn Image "tiefer" als dieses Image ist + if (image.y > this.y) { + angle = -angle; + } + + return angle; + } + + + /* DELETE */ + public void delete() { + bitmap.recycle(); + } + +} diff --git a/framework/Music.java b/framework/Music.java new file mode 100644 index 0000000..afeef22 --- /dev/null +++ b/framework/Music.java @@ -0,0 +1,79 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import android.media.MediaPlayer; + +import ofenbach.exampleapp.main.Settings; // change this to your package name + +/* Music.java to play simple background music in your app */ +/* @creation: May 2014 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class Music { + + // MediaPlayer + MediaPlayer mediaplayer; + + // Pfad + int path; + boolean isPrepared; + + + /* KONSTRUKTOR */ + public Music(int path) { + + this.path = path; + + // Musik laden + mediaplayer = new MediaPlayer(); + mediaplayer = MediaPlayer.create(Settings.context, path); + //mediaplayer.setLooping(true); + + } + + + /* PLAY */ + public void play() { + mediaplayer.start(); + } + + + /* STOP */ + public void stop() { + mediaplayer.stop(); + synchronized (this) { + isPrepared = false; + } + } + + + /* PAUSE */ + public void pause() { + if (mediaplayer.isPlaying()) { + mediaplayer.pause(); + } + } + + + /* LAUTSTAERKE */ + public void setVolume(float volume) { + mediaplayer.setVolume(volume, volume); + } + + + /* WIEDERHOLUNG */ + public void setLooping(boolean looping) { + mediaplayer.setLooping(looping); + } + + + /* DELETE */ + public void delete() { + if (mediaplayer.isPlaying()) { + mediaplayer.stop(); + } + mediaplayer.release(); + } + + +} diff --git a/framework/Sound.java b/framework/Sound.java new file mode 100644 index 0000000..3168d33 --- /dev/null +++ b/framework/Sound.java @@ -0,0 +1,44 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import android.media.AudioManager; +import android.media.SoundPool; + +import ofenbach.exampleapp.main.Settings; // change this to your package name + +/* to create simple sounds in your app (e.g. explosions, gunshots). */ +/* @creation: May 2014 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class Sound { + + SoundPool soundPool; + + // Path + int path; + + + /* CONSTRUCTOR */ + @SuppressWarnings("deprecation") + public Sound(int sound_direction) { + soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0); + this.path = soundPool.load(Settings.getContext(), sound_direction, 1); + } + + + /* PLAY */ + public void play() { + soundPool.play(path, 1, 1, 0, 0, 1); + } + + /* VOLUME */ + public void setVolume(double procent) { + soundPool.setVolume(path, (float) procent, (float) procent); + } + + /* DELETE */ + public void delete() { + soundPool.unload(path); + } + +} diff --git a/gamestuff/Particle.java b/gamestuff/Particle.java new file mode 100644 index 0000000..f1b946e --- /dev/null +++ b/gamestuff/Particle.java @@ -0,0 +1,30 @@ +package ofenbach.exampleapp.main; // change this to your package name + +import android.app.Activity; +import android.os.Bundle; +import android.widget.RelativeLayout; + +/* @creation: April 2018 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class Particle { + + // Leere Liste wo Bilder reinkönnen + + int current_pic; + int duration; // how long each pic will display / change between the pics + int complete_duration; // #pictures*duration + + public Particle(list pictures) { + + } + + public void setPictures(list pictures) {} // setup + + public void startAnimation() {} // trigger to start sprite + + public void draw() {} // put this in your repeat() + + +} \ No newline at end of file diff --git a/main/Camera.java b/main/Camera.java new file mode 100644 index 0000000..96e1303 --- /dev/null +++ b/main/Camera.java @@ -0,0 +1,16 @@ +package ofenbach.exampleapp.main; // change this to your package name + +/* to switch screens */ +/* @creation: March 2018 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class Camera { + + public static int currentscreen_id = 0; + + public static void setScreen(int id) { + currentscreen_id = id; + } + +} \ No newline at end of file diff --git a/main/MainActivity.java b/main/MainActivity.java new file mode 100644 index 0000000..5891534 --- /dev/null +++ b/main/MainActivity.java @@ -0,0 +1,33 @@ +package ofenbach.exampleapp.main; // change this to your package name + +import android.app.Activity; +import android.os.Bundle; +import android.widget.RelativeLayout; + +/* @creation: February 2014 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class MainActivity extends Activity { + + /** ONLY CHANGE THIS IF YOU KNOW WHAT YOU ARE DOING! **/ + + RelativeLayout layout; + MainView view; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Settings.context = this; + + layout = new RelativeLayout(this); + setContentView(layout); + + view = new MainView(); + layout.addView(view); + + } + + +} \ No newline at end of file diff --git a/main/MainView.java b/main/MainView.java new file mode 100644 index 0000000..74ff539 --- /dev/null +++ b/main/MainView.java @@ -0,0 +1,56 @@ +package ofenbach.exampleapp.main; // change this to your package name + +import android.graphics.Canvas; +import android.view.MotionEvent; +import android.view.View; + +import ofenbach.exampleapp.views.GameStart; // change this to your package name + +/* @creation: March 2018 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class MainView extends View { + + /** ONLY CHANGE THIS IF YOU KNOW WHAT YOU ARE DOING! **/ + + public static Canvas global_canvas; // used by Image.java to draw + + GameStart gamestart; + boolean first_time = true; + + public MainView() { + super(Settings.context); + + gamestart = new GameStart(); // start game + + } + + public void onDraw(Canvas c) { + + global_canvas = c; + + if (first_time) { // save screen size, start game + Settings.screen_height = c.getHeight(); + Settings.screen_width = c.getWidth(); + first_time = false; + gamestart.start(); + } + + Screen.screens.get(Camera.currentscreen_id).repeat(); // display current screen + + invalidate(); // repeat + + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + + TouchEvent.touch_event = ev; // update event + + Screen.screens.get(Camera.currentscreen_id).touch(); // trigger touch function in the right screen + + return true; + } + +} diff --git a/main/Screen.java b/main/Screen.java new file mode 100644 index 0000000..89c74b1 --- /dev/null +++ b/main/Screen.java @@ -0,0 +1,25 @@ +package ofenbach.exampleapp.main; // change this to your package name + +import java.util.ArrayList; +import java.util.List; + +/* Saves its own children, to know what screens there are and which one to display. */ +/* @creation: March 2018 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public abstract class Screen { + + public static List screens = new ArrayList<>(); // child list (used by Camera.java) + + public Screen() { + screens.add(this); // save child + } + + public void repeat() {} // loop 60FPS + + public void load() {} // when the screen starts + + public void touch() {} // triggered by touch + +} \ No newline at end of file diff --git a/main/Settings.java b/main/Settings.java new file mode 100644 index 0000000..db0c32c --- /dev/null +++ b/main/Settings.java @@ -0,0 +1,33 @@ +package ofenbach.exampleapp.main; // change this to your package name + +/* class with mostly statics, to save your app data and get device information */ +/* @creation: September 2016 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +import android.content.Context; + +public class Settings { + + public static Context context; + + public static int screen_height; + public static int screen_width; + + public static boolean sound_on = true; + + + public static Context getContext() { + return context; + } + + public static int getScreenHeight() { + return screen_height; + } + public static int getScreenWidth() { + return screen_width; + } + + + +} \ No newline at end of file diff --git a/main/TouchEvent.java b/main/TouchEvent.java new file mode 100644 index 0000000..72ffc29 --- /dev/null +++ b/main/TouchEvent.java @@ -0,0 +1,21 @@ +package ofenbach.exampleapp.main; // change this to your package name + +import android.view.MotionEvent; + +/* @creation: March 2018 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class TouchEvent { + + public static MotionEvent touch_event; // to access coordinations, action-event etc. + + public static int getX() { + return (int) touch_event.getX(); + } + + public static int getY() { + return (int) touch_event.getY(); + } + +} \ No newline at end of file From b2c770ff54f69253cc5497b1ada7191bc3f8e3df Mon Sep 17 00:00:00 2001 From: Tim Ofenbach Date: Wed, 25 Apr 2018 23:33:14 +0200 Subject: [PATCH 07/46] Create concepts.txt concept added --- concepts.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 concepts.txt diff --git a/concepts.txt b/concepts.txt new file mode 100644 index 0000000..617587c --- /dev/null +++ b/concepts.txt @@ -0,0 +1,6 @@ +Change R.drawable.player -> player in Image(path). +turn path from int to string! +then convert string to int dependent on the id!!! + +new Image(R.drawable.player) -> Image("player") +if file name is player From feed996e2ce82bc10e7bee330aea23551ce36810 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Sat, 28 Apr 2018 16:51:25 +0200 Subject: [PATCH 08/46] new update --- README.md | 4 - concepts.txt | 6 - {framework => engine/framework}/Button.java | 2 +- .../framework}/CollisionDetection.java | 5 +- {framework => engine/framework}/Image.java | 162 ++++++----- {framework => engine/framework}/Music.java | 54 ++-- {framework => engine/framework}/Sound.java | 23 +- engine/framework/Sprite.java | 100 +++++++ engine/main/Camera.java | 20 ++ engine/main/Device.java | 51 ++++ engine/main/MainActivity.java | 64 +++++ {main => engine/main}/MainView.java | 131 +++++---- {main => engine/main}/Screen.java | 59 ++-- engine/main/Settings.java | 30 ++ {main => engine/main}/TouchEvent.java | 45 +-- example/ExampleApp/.gitignore | 10 + .../.idea/caches/build_file_checksums.ser | Bin 0 -> 544 bytes .../ExampleApp/.idea/codeStyles/Project.xml | 29 ++ example/ExampleApp/.idea/gradle.xml | 18 ++ example/ExampleApp/.idea/misc.xml | 34 +++ .../ExampleApp/.idea/runConfigurations.xml | 12 + example/ExampleApp/app/.gitignore | 1 + example/ExampleApp/app/build.gradle | 26 ++ example/ExampleApp/app/proguard-rules.pro | 21 ++ .../main/ExampleInstrumentedTest.java | 26 ++ .../app/src/main/AndroidManifest.xml | 23 ++ .../ofenbach/exampleapp/framework/Button.java | 27 ++ .../framework/CollisionDetection.java | 64 +++++ .../ofenbach/exampleapp/framework/Image.java | 262 ++++++++++++++++++ .../ofenbach/exampleapp/framework/Music.java | 69 +++++ .../ofenbach/exampleapp/framework/Sound.java | 49 ++++ .../ofenbach/exampleapp/framework/Sprite.java | 100 +++++++ .../java/ofenbach/exampleapp/main/Camera.java | 20 ++ .../java/ofenbach/exampleapp/main/Device.java | 51 ++++ .../exampleapp/main/MainActivity.java | 64 +++++ .../ofenbach/exampleapp/main/MainView.java | 75 +++++ .../java/ofenbach/exampleapp/main/Screen.java | 34 +++ .../ofenbach/exampleapp/main/Settings.java | 30 ++ .../ofenbach/exampleapp/main/TouchEvent.java | 24 ++ .../exampleapp/views/ExampleScreen.java | 110 ++++++++ .../ofenbach/exampleapp/views/GameStart.java | 25 ++ .../drawable-v24/ic_launcher_foreground.xml | 34 +++ .../app/src/main/res/drawable/backdrop.png | Bin 0 -> 4577 bytes .../app/src/main/res/drawable/dust_1.png | Bin 0 -> 219 bytes .../app/src/main/res/drawable/dust_2.png | Bin 0 -> 269 bytes .../app/src/main/res/drawable/dust_3.png | Bin 0 -> 284 bytes .../app/src/main/res/drawable/dust_4.png | Bin 0 -> 300 bytes .../app/src/main/res/drawable/dust_5.png | Bin 0 -> 287 bytes .../app/src/main/res/drawable/dust_6.png | Bin 0 -> 226 bytes .../app/src/main/res/drawable/dust_7.png | Bin 0 -> 181 bytes .../app/src/main/res/drawable/floor_1.png | Bin 0 -> 1205 bytes .../app/src/main/res/drawable/floor_2.png | Bin 0 -> 949 bytes .../app/src/main/res/drawable/floor_3.png | Bin 0 -> 473 bytes .../res/drawable/ic_launcher_background.xml | 170 ++++++++++++ .../app/src/main/res/drawable/player.png | Bin 0 -> 472 bytes .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes .../app/src/main/res/values/colors.xml | 6 + .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 8 + .../exampleapp/main/ExampleUnitTest.java | 17 ++ example/ExampleApp/build.gradle | 27 ++ example/ExampleApp/gradle.properties | 13 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54708 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + example/ExampleApp/gradlew | 172 ++++++++++++ example/ExampleApp/gradlew.bat | 84 ++++++ example/ExampleApp/settings.gradle | 1 + gamestuff/Particle.java | 30 -- main/Camera.java | 16 -- main/MainActivity.java | 33 --- main/Settings.java | 33 --- 82 files changed, 2278 insertions(+), 345 deletions(-) delete mode 100644 README.md delete mode 100644 concepts.txt rename {framework => engine/framework}/Button.java (99%) rename {framework => engine/framework}/CollisionDetection.java (94%) rename {framework => engine/framework}/Image.java (72%) rename {framework => engine/framework}/Music.java (72%) rename {framework => engine/framework}/Sound.java (70%) create mode 100644 engine/framework/Sprite.java create mode 100644 engine/main/Camera.java create mode 100644 engine/main/Device.java create mode 100644 engine/main/MainActivity.java rename {main => engine/main}/MainView.java (51%) rename {main => engine/main}/Screen.java (56%) create mode 100644 engine/main/Settings.java rename {main => engine/main}/TouchEvent.java (81%) create mode 100644 example/ExampleApp/.gitignore create mode 100644 example/ExampleApp/.idea/caches/build_file_checksums.ser create mode 100644 example/ExampleApp/.idea/codeStyles/Project.xml create mode 100644 example/ExampleApp/.idea/gradle.xml create mode 100644 example/ExampleApp/.idea/misc.xml create mode 100644 example/ExampleApp/.idea/runConfigurations.xml create mode 100644 example/ExampleApp/app/.gitignore create mode 100644 example/ExampleApp/app/build.gradle create mode 100644 example/ExampleApp/app/proguard-rules.pro create mode 100644 example/ExampleApp/app/src/androidTest/java/ofenbach/exampleapp/main/ExampleInstrumentedTest.java create mode 100644 example/ExampleApp/app/src/main/AndroidManifest.xml create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Button.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/CollisionDetection.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Image.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Music.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Sound.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Sprite.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/Camera.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/Device.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/MainActivity.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/MainView.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/Screen.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/Settings.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/TouchEvent.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/ExampleScreen.java create mode 100644 example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/GameStart.java create mode 100644 example/ExampleApp/app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 example/ExampleApp/app/src/main/res/drawable/backdrop.png create mode 100644 example/ExampleApp/app/src/main/res/drawable/dust_1.png create mode 100644 example/ExampleApp/app/src/main/res/drawable/dust_2.png create mode 100644 example/ExampleApp/app/src/main/res/drawable/dust_3.png create mode 100644 example/ExampleApp/app/src/main/res/drawable/dust_4.png create mode 100644 example/ExampleApp/app/src/main/res/drawable/dust_5.png create mode 100644 example/ExampleApp/app/src/main/res/drawable/dust_6.png create mode 100644 example/ExampleApp/app/src/main/res/drawable/dust_7.png create mode 100644 example/ExampleApp/app/src/main/res/drawable/floor_1.png create mode 100644 example/ExampleApp/app/src/main/res/drawable/floor_2.png create mode 100644 example/ExampleApp/app/src/main/res/drawable/floor_3.png create mode 100644 example/ExampleApp/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 example/ExampleApp/app/src/main/res/drawable/player.png create mode 100644 example/ExampleApp/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 example/ExampleApp/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 example/ExampleApp/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 example/ExampleApp/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 example/ExampleApp/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 example/ExampleApp/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 example/ExampleApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 example/ExampleApp/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 example/ExampleApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 example/ExampleApp/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 example/ExampleApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 example/ExampleApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 example/ExampleApp/app/src/main/res/values/colors.xml create mode 100644 example/ExampleApp/app/src/main/res/values/strings.xml create mode 100644 example/ExampleApp/app/src/main/res/values/styles.xml create mode 100644 example/ExampleApp/app/src/test/java/ofenbach/exampleapp/main/ExampleUnitTest.java create mode 100644 example/ExampleApp/build.gradle create mode 100644 example/ExampleApp/gradle.properties create mode 100644 example/ExampleApp/gradle/wrapper/gradle-wrapper.jar create mode 100644 example/ExampleApp/gradle/wrapper/gradle-wrapper.properties create mode 100644 example/ExampleApp/gradlew create mode 100644 example/ExampleApp/gradlew.bat create mode 100644 example/ExampleApp/settings.gradle delete mode 100644 gamestuff/Particle.java delete mode 100644 main/Camera.java delete mode 100644 main/MainActivity.java delete mode 100644 main/Settings.java diff --git a/README.md b/README.md deleted file mode 100644 index 3611af3..0000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# new features -+ ̶i̶̶n̶̶d̶̶e̶̶p̶̶e̶̶n̶̶d̶̶e̶̶n̶̶t̶̶ ̶̶p̶̶o̶̶s̶̶i̶̶t̶̶i̶̶o̶̶n̶̶s̶ -+ particle class -+ ̶g̶̶r̶̶a̶̶v̶̶i̶̶t̶̶y̶̶ ̶̶f̶̶u̶̶n̶̶c̶̶t̶̶i̶̶o̶̶n̶ diff --git a/concepts.txt b/concepts.txt deleted file mode 100644 index 617587c..0000000 --- a/concepts.txt +++ /dev/null @@ -1,6 +0,0 @@ -Change R.drawable.player -> player in Image(path). -turn path from int to string! -then convert string to int dependent on the id!!! - -new Image(R.drawable.player) -> Image("player") -if file name is player diff --git a/framework/Button.java b/engine/framework/Button.java similarity index 99% rename from framework/Button.java rename to engine/framework/Button.java index 66ab4a3..2b70889 100644 --- a/framework/Button.java +++ b/engine/framework/Button.java @@ -24,4 +24,4 @@ public boolean isPressed() { } -} +} \ No newline at end of file diff --git a/framework/CollisionDetection.java b/engine/framework/CollisionDetection.java similarity index 94% rename from framework/CollisionDetection.java rename to engine/framework/CollisionDetection.java index b74d1e3..59157b0 100644 --- a/framework/CollisionDetection.java +++ b/engine/framework/CollisionDetection.java @@ -5,9 +5,6 @@ import android.graphics.Rect; /* used by Image.java to detect collision between two images. */ -/* @creation: September 2016 */ -/* @update: 25.4.2018 */ -/* @author: Tim B. Ofenbach */ public class CollisionDetection { @@ -64,4 +61,4 @@ private static boolean isFilled(int pixel) { return pixel != Color.TRANSPARENT; } -} +} \ No newline at end of file diff --git a/framework/Image.java b/engine/framework/Image.java similarity index 72% rename from framework/Image.java rename to engine/framework/Image.java index 7480e37..e7f3801 100644 --- a/framework/Image.java +++ b/engine/framework/Image.java @@ -5,15 +5,20 @@ import android.graphics.Matrix; import android.graphics.Paint; +import ofenbach.exampleapp.main.Device; +import ofenbach.exampleapp.main.MainActivity; import ofenbach.exampleapp.main.MainView; // change this to your package name -import ofenbach.exampleapp.main.Settings; // change this to your package name -/* able to display .png pictures */ -/* @creation: February 2014 */ -/* @update: 26.4.2018 */ -/* @new: relative positions */ -/* @author: Tim B. Ofenbach */ +/* able to display .png pictures*/ +/* @creation: February 2014 */ +/* @update: 28.4.2018 */ +/* @author: Tim B. Ofenbach */ +/* update news 28.4.2018: + + added auomatic positions + + added gravity support + + improved comments + */ public class Image { @@ -26,29 +31,27 @@ public class Image { public double y = 0; // height: 1080 int angle; - // Matrix & Paint + // Matrix & Paint (rotation & transparency) Matrix m; Paint p; - + // Gravity - double gravity_factor; - double gravity_timer; + public double gravity_factor; + public double gravity_timer; /* CONSTRUCTOR */ public Image(int path) { - - // Parameter - this.path = path; - - // Erzeugung + + this.path = path; // parameter update + m = new Matrix(); p = new Paint(); // Bitmap Creation BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false; - bitmap = BitmapFactory.decodeResource(Settings.context.getResources(), path, options); + bitmap = BitmapFactory.decodeResource(MainActivity.context.getResources(), path, options); } @@ -59,8 +62,13 @@ public void draw() { // Anglesettings m.reset(); m.postRotate(angle, bitmap.getWidth() / 2, bitmap.getHeight() / 2); - m.postTranslate((float) ((x/1920)*Settings.getScreenWidth), (float) ((y/1080)*Settings.getScreenHeight)); - + m.postTranslate((float) (x/1920)*Device.get_screen_width(), (float) (y/1080)*Device.get_screen_height()); + + // Gravity + if (gravity_factor != 0) { + this.applyGravity(); + } + // Draw MainView.global_canvas.drawBitmap(bitmap, m, p); @@ -73,7 +81,7 @@ public void scale(double factor) { // Calculation double relativewidth = 1080 / (factor * bitmap.getWidth()); double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); - double width = Settings.getScreenWidth() / relativewidth; + double width = Device.get_screen_width() / relativewidth; double height = ratio * width; // Scaling @@ -81,15 +89,13 @@ public void scale(double factor) { } public void scaleFullscreen() { - bitmap = Bitmap.createScaledBitmap(bitmap, Settings.getScreenWidth(), Settings.getScreenHeight(), false); + bitmap = Bitmap.createScaledBitmap(bitmap, Device.get_screen_width(), Device.get_screen_height(), false); } public void scale() { - /* SCALING FOR SCRATCH */ - // Calculation double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); - double realwidth = Settings.getScreenWidth() * ((double) bitmap.getWidth()*2 / 480); + double realwidth = Device.get_screen_width() * ((double) bitmap.getWidth()*2 / 480); double realheight = realwidth * ratio;; // Scaling @@ -97,13 +103,15 @@ public void scale() { } public void scaleHalf() { - // fuer bilder die doppelt so gross sind (halbe pixel) + + // Calculation double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); - double realwidth = Settings.getScreenWidth() * ((double) bitmap.getWidth() / 480); + double realwidth = Device.get_screen_width() * ((double) bitmap.getWidth() / 480); double realheight = realwidth * ratio;; // Scaling bitmap = Bitmap.createScaledBitmap(bitmap, (int) realwidth, (int) realheight, false); + } @@ -130,13 +138,15 @@ public void setX(double xPos) { this.x = xPos; } public void setXtoMiddle() { - this.x = Settings.getScreenWidth() / 2 - this.getWidth() / 2; + //this.x = Device.get_screen_width() / 2 - this.getWidth() / 2; // old way + x = 1920 / 2 - getWidth() / 2; } public void setY(double yPos) { this.y = yPos; } public void setYtoMiddle() { - this.y = Settings.getScreenHeight() / 2 - this.getHeight() / 2; + //this.y = Device.get_screen_height() / 2 - this.getHeight() / 2; // old way: relative but still absolut + y = 1080 / 2 - getHeight() / 2; // new way: relative/automatic } public void setRotation(double angle) { this.angle = (int) angle; @@ -162,62 +172,21 @@ public int getHeight() { public int getAngle() { return angle; } - public int getAlpha() { - return p.getAlpha(); - } - public Bitmap getBitMap() { - return bitmap; - } - - - /* COLLISION */ - public boolean collidesWith(Image image) { - - // See CollisionDetection.java - return CollisionDetection.isCollisionDetected(bitmap, (int) x, (int) y, image.bitmap, (int) image.x, (int) image.y); - - } - - /* GRAVITY */ - public void setGravity(double factor) { // e.g. factor=9.81, factor = 0 -> false, factor != 0 -> true - this.gravity_factor = factor; - } - public void applyGravity() { // updates gravity movement (put this in your repeat() - this.y += gravity_timer*gravity_factor; - this.gravity_timer ++; - } - - - /* ON SCREEN? */ - public boolean isInScreen() { - if (this.x > -this.getWidth() && this.x < Settings.getScreenWidth()) { - if (this.y > -this.getHeight() && this.y < Settings.getScreenHeight()) { - return true; - } else { - return false; - } - } else { - return false; - } - } - - - // Extra Stuff public double getAngleTo(Image image) { - + // Vars double delta_x; double delta_y; double hypo; // Pythagoras double angle = 0; - + // ∆-X if (image.x > this.x) { delta_x = image.x - this.x; } else { delta_x = this.x - image.x; } - + // ∆Y // Wenn Image unter diesem Image if (image.y > this.y) { @@ -225,26 +194,69 @@ public double getAngleTo(Image image) { } else { // Wenn Image ueber diesem Image delta_y = this.y - image.y; } - + // Satz des Pythagoras a^2 + b^2 = c^2 // <=> sin(alpha) = Gegenkathete (∆x) / Hypothenuse (Wurzel aus (∆x^2 + ∆y^2)) // <=> alpha = arcsin(∆x / (sqrt(∆x^2+∆y^2) hypo = Math.sqrt(delta_x*delta_x + delta_y*delta_y); angle = Math.asin( delta_y / hypo ); // alpha = arcsin(gegenkathete / hypo) angle = Math.toDegrees(angle); - + // Umkehrung des Winkels wenn Image "tiefer" als dieses Image ist if (image.y > this.y) { angle = -angle; } - + return angle; } + public int getAlpha() { + return p.getAlpha(); + } + public Bitmap getBitMap() { + return bitmap; + } + + + /* COLLISION */ + public boolean collidesWith(Image image) { + + // See CollisionDetection.java + return CollisionDetection.isCollisionDetected(bitmap, (int) x, (int) y, image.bitmap, (int) image.x, (int) image.y); + + } + + + /* GRAVITY */ + public void setGravity(double factor) { // e.g. factor=9.81, factor = 0 -> false, factor != 0 -> true + this.gravity_factor = factor; + } + public void applyGravity() { // updates gravity movement (put this in your repeat()) + this.y += gravity_timer* gravity_factor; + this.gravity_timer += 0.016*4; + } + public void increaseGravity(int increase) { + this.gravity_timer += increase; + } + + /* ON SCREEN? */ + public boolean isInScreen() { + if (this.x > -this.getWidth() && this.x < Device.get_screen_width()) { + if (this.y > -this.getHeight() && this.y < Device.get_screen_height()) { + return true; + } else { + return false; + } + } else { + return false; + } + } + /* DELETE */ public void delete() { bitmap.recycle(); } -} + +} \ No newline at end of file diff --git a/framework/Music.java b/engine/framework/Music.java similarity index 72% rename from framework/Music.java rename to engine/framework/Music.java index afeef22..e01da8f 100644 --- a/framework/Music.java +++ b/engine/framework/Music.java @@ -2,72 +2,62 @@ import android.media.MediaPlayer; +import ofenbach.exampleapp.main.MainActivity; import ofenbach.exampleapp.main.Settings; // change this to your package name /* Music.java to play simple background music in your app */ /* @creation: May 2014 */ -/* @update: 25.4.2018 */ +/* @update: 28.4.2018 */ /* @author: Tim B. Ofenbach */ +/* update news 28.4.2018: + + turns off when Settings.sound_on is false + - removed unnecessary comments + */ + public class Music { - // MediaPlayer MediaPlayer mediaplayer; - - // Pfad + int path; boolean isPrepared; - - - /* KONSTRUKTOR */ + public Music(int path) { - this.path = path; - - // Musik laden + this.path = path; // update path + mediaplayer = new MediaPlayer(); - mediaplayer = MediaPlayer.create(Settings.context, path); - //mediaplayer.setLooping(true); + mediaplayer = MediaPlayer.create(MainActivity.context, path); // load music } - - - /* PLAY */ + public void play() { - mediaplayer.start(); + if (Settings.sound_enabled()) { + mediaplayer.start(); + } } - - - /* STOP */ + public void stop() { mediaplayer.stop(); synchronized (this) { isPrepared = false; } } - - - /* PAUSE */ + public void pause() { if (mediaplayer.isPlaying()) { mediaplayer.pause(); } } - - - /* LAUTSTAERKE */ + public void setVolume(float volume) { mediaplayer.setVolume(volume, volume); } - - - /* WIEDERHOLUNG */ + public void setLooping(boolean looping) { mediaplayer.setLooping(looping); } - - - /* DELETE */ + public void delete() { if (mediaplayer.isPlaying()) { mediaplayer.stop(); @@ -76,4 +66,4 @@ public void delete() { } -} +} \ No newline at end of file diff --git a/framework/Sound.java b/engine/framework/Sound.java similarity index 70% rename from framework/Sound.java rename to engine/framework/Sound.java index 3168d33..d5382ba 100644 --- a/framework/Sound.java +++ b/engine/framework/Sound.java @@ -3,6 +3,7 @@ import android.media.AudioManager; import android.media.SoundPool; +import ofenbach.exampleapp.main.MainActivity; import ofenbach.exampleapp.main.Settings; // change this to your package name /* to create simple sounds in your app (e.g. explosions, gunshots). */ @@ -10,35 +11,39 @@ /* @update: 25.4.2018 */ /* @author: Tim B. Ofenbach */ +/* update news 28.4.2018: + + turns off when Settings.sound_on is false + - removed unnecessary comments + */ + + public class Sound { SoundPool soundPool; - // Path int path; - /* CONSTRUCTOR */ - @SuppressWarnings("deprecation") public Sound(int sound_direction) { soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0); - this.path = soundPool.load(Settings.getContext(), sound_direction, 1); + this.path = soundPool.load(MainActivity.context, sound_direction, 1); } - /* PLAY */ public void play() { - soundPool.play(path, 1, 1, 0, 0, 1); + if (Settings.sound_enabled()) { + soundPool.play(path, 1, 1, 0, 0, 1); + } } - /* VOLUME */ + public void setVolume(double procent) { soundPool.setVolume(path, (float) procent, (float) procent); } - /* DELETE */ + public void delete() { soundPool.unload(path); } -} +} \ No newline at end of file diff --git a/engine/framework/Sprite.java b/engine/framework/Sprite.java new file mode 100644 index 0000000..63d7115 --- /dev/null +++ b/engine/framework/Sprite.java @@ -0,0 +1,100 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import java.util.ArrayList; +import java.util.List; + +/* @creation: 28.4.2018 */ +/* @update: - */ +/* @author: Tim B. Ofenbach */ + +public class Sprite { + + public List images = new ArrayList<>(); // list with pictures + + int current_pic; // current pic to display + double duration; // how long each pic will display / change between the pics (in sec) + double complete_duration; // #pictures*duration + boolean animation; // to start the animation + double timer; // animationtimer + + + public Sprite(int[] pictures, double duration) { + + // parameter update + this.duration = duration; + this.timer = duration; + this.complete_duration = pictures.length * duration; + + // load + for (int i = 0; i screens = new ArrayList<>(); // child list (used by Camera.java) - - public Screen() { - screens.add(this); // save child - } - - public void repeat() {} // loop 60FPS - - public void load() {} // when the screen starts - - public void touch() {} // triggered by touch - -} \ No newline at end of file +package ofenbach.exampleapp.main; // change this to your package name + +import java.util.ArrayList; +import java.util.List; + +/* Saves its own children, to know what screens there are and which one to display. */ +/* @creation: March 2018 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class Screen { + + /* Explanation: */ + /* acts as a superclass for your screens. */ + /* here are all the screens which were created stored */ + /* MainView displays the right screen (id stored at Camera) via this list */ + + public static List screens = new ArrayList<>(); // child list (used by MainView to display the right screen) + + public Screen() { + screens.add(this); // save child + } + + public void repeat() {} // loop 60FPS + + public void load() {} // when the screen starts + + public void touchHold() {} // triggered by touch + + public void touchDown() {} + + public void touchUp() { } + +} diff --git a/engine/main/Settings.java b/engine/main/Settings.java new file mode 100644 index 0000000..82b13d6 --- /dev/null +++ b/engine/main/Settings.java @@ -0,0 +1,30 @@ +package ofenbach.exampleapp.main; // change this to your package name + +/* class with mostly statics, to save your app settings */ +/* @creation: September 2016 */ +/* @update: 28.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class Settings { + + /* Explanation: */ + /* You should also save your app settings (e.g. sound on) here. */ + + public static boolean sound_on = Device.getSavingBool("sound_on"); + + + public static void set_sound_enabled(boolean bool) { + sound_on = bool; + // save + if (bool) { + Device.setSaving("sound_on", 1); + } else { + Device.setSaving("sound_on", 0); + } + } + public static boolean sound_enabled() { + return sound_on; + } + + +} diff --git a/main/TouchEvent.java b/engine/main/TouchEvent.java similarity index 81% rename from main/TouchEvent.java rename to engine/main/TouchEvent.java index 72ffc29..51cd2a2 100644 --- a/main/TouchEvent.java +++ b/engine/main/TouchEvent.java @@ -1,21 +1,24 @@ -package ofenbach.exampleapp.main; // change this to your package name - -import android.view.MotionEvent; - -/* @creation: March 2018 */ -/* @update: 25.4.2018 */ -/* @author: Tim B. Ofenbach */ - -public class TouchEvent { - - public static MotionEvent touch_event; // to access coordinations, action-event etc. - - public static int getX() { - return (int) touch_event.getX(); - } - - public static int getY() { - return (int) touch_event.getY(); - } - -} \ No newline at end of file +package ofenbach.exampleapp.main; // change this to your package name + +import android.view.MotionEvent; + +/* @creation: March 2018 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class TouchEvent { + + /* Explanation: */ + /* touch-events can be accessed now from everywhere thanks to this class */ + + public static MotionEvent touch_event; // to access coordinations, action-event etc. + + public static int getX() { + return (int) touch_event.getX(); + } + + public static int getY() { + return (int) touch_event.getY(); + } + +} diff --git a/example/ExampleApp/.gitignore b/example/ExampleApp/.gitignore new file mode 100644 index 0000000..5edb4ee --- /dev/null +++ b/example/ExampleApp/.gitignore @@ -0,0 +1,10 @@ +*.iml +.gradle +/local.properties +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/example/ExampleApp/.idea/caches/build_file_checksums.ser b/example/ExampleApp/.idea/caches/build_file_checksums.ser new file mode 100644 index 0000000000000000000000000000000000000000..c8c46103b858cac05e79c58a845b20bdabe6f811 GIT binary patch literal 544 zcmZ4UmVvdnh`~NNKUXg?FQq6yGexf?KR>5fFEb@IQ7^qHF(oHeub?PDD>b=9F91S2 zm1gFoxMk*~I%lLNXBU^|7Q2L-Ts|(GuF1r}HGbRpFnpBg5>l-a(W(##Th_( zR`y#54~r#SWM*J;W8likPfT%3OfJbU@?_vF$tX%K&dAS6sVJ~_U;qK0at2z_zyOYkOxc*3?Qo+1ZE4W3U*wHSbub5T43|f*>ylC z7N?e!Wagz8!!#B$)G@Gu)Xuw^u+Qc`d!BBBo>aKg;e{m(`p#A{p~b01#W6r%EBL3S z<|QR2XT(5t#vlT;AhoC@Gqt!BZq^mqo}2v)n^;~paL#!1!wG0F4~lEy3Jb~?6-Qf4 zc~$T=QKl(0)D-Booc!d(98ff2n0k}tzVo|;EAJ01pY^@UgbK|F5w+{?UbPr_2a OO}1&q&&~=YRR92-*1=o= literal 0 HcmV?d00001 diff --git a/example/ExampleApp/.idea/codeStyles/Project.xml b/example/ExampleApp/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..30aa626 --- /dev/null +++ b/example/ExampleApp/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/ExampleApp/.idea/gradle.xml b/example/ExampleApp/.idea/gradle.xml new file mode 100644 index 0000000..7ac24c7 --- /dev/null +++ b/example/ExampleApp/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/example/ExampleApp/.idea/misc.xml b/example/ExampleApp/.idea/misc.xml new file mode 100644 index 0000000..99202cc --- /dev/null +++ b/example/ExampleApp/.idea/misc.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/example/ExampleApp/.idea/runConfigurations.xml b/example/ExampleApp/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/example/ExampleApp/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/example/ExampleApp/app/.gitignore b/example/ExampleApp/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/example/ExampleApp/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/example/ExampleApp/app/build.gradle b/example/ExampleApp/app/build.gradle new file mode 100644 index 0000000..6305b95 --- /dev/null +++ b/example/ExampleApp/app/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 27 + defaultConfig { + applicationId "ofenbach.exampleapp.main" + minSdkVersion 15 + targetSdkVersion 27 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.1' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' +} diff --git a/example/ExampleApp/app/proguard-rules.pro b/example/ExampleApp/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/example/ExampleApp/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/example/ExampleApp/app/src/androidTest/java/ofenbach/exampleapp/main/ExampleInstrumentedTest.java b/example/ExampleApp/app/src/androidTest/java/ofenbach/exampleapp/main/ExampleInstrumentedTest.java new file mode 100644 index 0000000..a7f3ebb --- /dev/null +++ b/example/ExampleApp/app/src/androidTest/java/ofenbach/exampleapp/main/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package ofenbach.exampleapp.main; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("ofenbach.exampleapp.main", appContext.getPackageName()); + } +} diff --git a/example/ExampleApp/app/src/main/AndroidManifest.xml b/example/ExampleApp/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6c9d143 --- /dev/null +++ b/example/ExampleApp/app/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Button.java b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Button.java new file mode 100644 index 0000000..2b70889 --- /dev/null +++ b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Button.java @@ -0,0 +1,27 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import ofenbach.exampleapp.main.TouchEvent; // change this to your package name + +/* Same as Image.java but can register touch */ +/* @creation: March 2014 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class Button extends Image { + + public Button(int path) { + super(path); + } + + public boolean isPressed() { + + // Touch coords + int touchX = TouchEvent.getX(); + int touchY = TouchEvent.getY(); + + // Hitbox check + return (touchX > super.getX() && touchX < super.getX() + super.getWidth() && touchY > super.getY() && touchY < super.getY() + super.getHeight()); + + } + +} \ No newline at end of file diff --git a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/CollisionDetection.java b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/CollisionDetection.java new file mode 100644 index 0000000..59157b0 --- /dev/null +++ b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/CollisionDetection.java @@ -0,0 +1,64 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Rect; + +/* used by Image.java to detect collision between two images. */ + +public class CollisionDetection { + + /** + * @param bitmap1 First bitmap + * @param x1 x-position of bitmap1 on screen. + * @param y1 y-position of bitmap1 on screen. + * @param bitmap2 second bitmap + * @param x2 x-position of bitmap2 on screen. + * @param y2 y-position of bitmap2 on screen. + */ + + public static boolean isCollisionDetected(Bitmap bitmap1, int x1, int y1, Bitmap bitmap2, int x2, int y2) { + + Rect bounds1 = new Rect(x1, y1, x1+bitmap1.getWidth(), y1+bitmap1.getHeight()); + Rect bounds2 = new Rect(x2, y2, x2+bitmap2.getWidth(), y2+bitmap2.getHeight()); + + if (Rect.intersects(bounds1, bounds2)) { + Rect collisionBounds = getCollisionBounds(bounds1, bounds2); + + for (int i = collisionBounds.left; i < collisionBounds.right; i++) { + + for (int j = collisionBounds.top; j < collisionBounds.bottom; j++) { + + int bitmap1Pixel = bitmap1.getPixel(i-x1, j-y1); + int bitmap2Pixel = bitmap2.getPixel(i-x2, j-y2); + + if (isFilled(bitmap1Pixel) && isFilled(bitmap2Pixel)) { + return true; + } + + } + + } + + } + + return false; + + } + + private static Rect getCollisionBounds(Rect rect1, Rect rect2) { + + int left = (int) Math.max(rect1.left, rect2.left); + int top = (int) Math.max(rect1.top, rect2.top); + int right = (int) Math.min(rect1.right, rect2.right); + int bottom = (int) Math.min(rect1.bottom, rect2.bottom); + + return new Rect(left, top, right, bottom); + + } + + private static boolean isFilled(int pixel) { + return pixel != Color.TRANSPARENT; + } + +} \ No newline at end of file diff --git a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Image.java b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Image.java new file mode 100644 index 0000000..e7f3801 --- /dev/null +++ b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Image.java @@ -0,0 +1,262 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.graphics.Paint; + +import ofenbach.exampleapp.main.Device; +import ofenbach.exampleapp.main.MainActivity; +import ofenbach.exampleapp.main.MainView; // change this to your package name + +/* able to display .png pictures*/ +/* @creation: February 2014 */ +/* @update: 28.4.2018 */ +/* @author: Tim B. Ofenbach */ + +/* update news 28.4.2018: + + added auomatic positions + + added gravity support + + improved comments + */ + +public class Image { + + // Bitmap & Path + Bitmap bitmap; + int path; + + // Position & Angle + public double x = 0; // width: 1920 + public double y = 0; // height: 1080 + int angle; + + // Matrix & Paint (rotation & transparency) + Matrix m; + Paint p; + + // Gravity + public double gravity_factor; + public double gravity_timer; + + + /* CONSTRUCTOR */ + public Image(int path) { + + this.path = path; // parameter update + + m = new Matrix(); + p = new Paint(); + + // Bitmap Creation + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inScaled = false; + bitmap = BitmapFactory.decodeResource(MainActivity.context.getResources(), path, options); + + } + + + /* DRAW */ + public void draw() { + + // Anglesettings + m.reset(); + m.postRotate(angle, bitmap.getWidth() / 2, bitmap.getHeight() / 2); + m.postTranslate((float) (x/1920)*Device.get_screen_width(), (float) (y/1080)*Device.get_screen_height()); + + // Gravity + if (gravity_factor != 0) { + this.applyGravity(); + } + + // Draw + MainView.global_canvas.drawBitmap(bitmap, m, p); + + } + + + /* SCALING */ + public void scale(double factor) { + + // Calculation + double relativewidth = 1080 / (factor * bitmap.getWidth()); + double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); + double width = Device.get_screen_width() / relativewidth; + double height = ratio * width; + + // Scaling + bitmap = Bitmap.createScaledBitmap(bitmap, (int) width, (int) height, false); + + } + public void scaleFullscreen() { + bitmap = Bitmap.createScaledBitmap(bitmap, Device.get_screen_width(), Device.get_screen_height(), false); + } + public void scale() { + + // Calculation + double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); + double realwidth = Device.get_screen_width() * ((double) bitmap.getWidth()*2 / 480); + double realheight = realwidth * ratio;; + + // Scaling + bitmap = Bitmap.createScaledBitmap(bitmap, (int) realwidth, (int) realheight, false); + + } + public void scaleHalf() { + + // Calculation + double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); + double realwidth = Device.get_screen_width() * ((double) bitmap.getWidth() / 480); + double realheight = realwidth * ratio;; + + // Scaling + bitmap = Bitmap.createScaledBitmap(bitmap, (int) realwidth, (int) realheight, false); + + } + + + /* SET FUNCTIONS */ + public void setAlpha(int alpha) { + p.setAlpha(alpha); + } + public void move(double distance) { + + // Calculation + double distanceX = distance * Math.sin(angle); + double distanceY = distance * Math.cos(angle); + + // Update X Y + x += distanceX; + y += distanceY; + + } + public void goTo(int xPos, int yPos) { + x = xPos; + y = yPos; + } + public void setX(double xPos) { + this.x = xPos; + } + public void setXtoMiddle() { + //this.x = Device.get_screen_width() / 2 - this.getWidth() / 2; // old way + x = 1920 / 2 - getWidth() / 2; + } + public void setY(double yPos) { + this.y = yPos; + } + public void setYtoMiddle() { + //this.y = Device.get_screen_height() / 2 - this.getHeight() / 2; // old way: relative but still absolut + y = 1080 / 2 - getHeight() / 2; // new way: relative/automatic + } + public void setRotation(double angle) { + this.angle = (int) angle; + m.reset(); + m.postRotate((int) angle, bitmap.getWidth() / 2, bitmap.getHeight() / 2); + m.postTranslate((int) x, (int) y); + } + + + /* GET FUNCTIONS */ + public double getX() { + return x; + } + public double getY() { + return y; + } + public int getWidth() { + return bitmap.getWidth(); + } + public int getHeight() { + return bitmap.getHeight(); + } + public int getAngle() { + return angle; + } + public double getAngleTo(Image image) { + + // Vars + double delta_x; + double delta_y; + double hypo; // Pythagoras + double angle = 0; + + // ∆-X + if (image.x > this.x) { + delta_x = image.x - this.x; + } else { + delta_x = this.x - image.x; + } + + // ∆Y + // Wenn Image unter diesem Image + if (image.y > this.y) { + delta_y = image.y - this.y; + } else { // Wenn Image ueber diesem Image + delta_y = this.y - image.y; + } + + // Satz des Pythagoras a^2 + b^2 = c^2 + // <=> sin(alpha) = Gegenkathete (∆x) / Hypothenuse (Wurzel aus (∆x^2 + ∆y^2)) + // <=> alpha = arcsin(∆x / (sqrt(∆x^2+∆y^2) + hypo = Math.sqrt(delta_x*delta_x + delta_y*delta_y); + angle = Math.asin( delta_y / hypo ); // alpha = arcsin(gegenkathete / hypo) + angle = Math.toDegrees(angle); + + // Umkehrung des Winkels wenn Image "tiefer" als dieses Image ist + if (image.y > this.y) { + angle = -angle; + } + + return angle; + } + public int getAlpha() { + return p.getAlpha(); + } + public Bitmap getBitMap() { + return bitmap; + } + + + /* COLLISION */ + public boolean collidesWith(Image image) { + + // See CollisionDetection.java + return CollisionDetection.isCollisionDetected(bitmap, (int) x, (int) y, image.bitmap, (int) image.x, (int) image.y); + + } + + + /* GRAVITY */ + public void setGravity(double factor) { // e.g. factor=9.81, factor = 0 -> false, factor != 0 -> true + this.gravity_factor = factor; + } + public void applyGravity() { // updates gravity movement (put this in your repeat()) + this.y += gravity_timer* gravity_factor; + this.gravity_timer += 0.016*4; + } + public void increaseGravity(int increase) { + this.gravity_timer += increase; + } + + + /* ON SCREEN? */ + public boolean isInScreen() { + if (this.x > -this.getWidth() && this.x < Device.get_screen_width()) { + if (this.y > -this.getHeight() && this.y < Device.get_screen_height()) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + + /* DELETE */ + public void delete() { + bitmap.recycle(); + } + + +} \ No newline at end of file diff --git a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Music.java b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Music.java new file mode 100644 index 0000000..e01da8f --- /dev/null +++ b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Music.java @@ -0,0 +1,69 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import android.media.MediaPlayer; + +import ofenbach.exampleapp.main.MainActivity; +import ofenbach.exampleapp.main.Settings; // change this to your package name + +/* Music.java to play simple background music in your app */ +/* @creation: May 2014 */ +/* @update: 28.4.2018 */ +/* @author: Tim B. Ofenbach */ + +/* update news 28.4.2018: + + turns off when Settings.sound_on is false + - removed unnecessary comments + */ + +public class Music { + + MediaPlayer mediaplayer; + + int path; + boolean isPrepared; + + public Music(int path) { + + this.path = path; // update path + + mediaplayer = new MediaPlayer(); + mediaplayer = MediaPlayer.create(MainActivity.context, path); // load music + + } + + public void play() { + if (Settings.sound_enabled()) { + mediaplayer.start(); + } + } + + public void stop() { + mediaplayer.stop(); + synchronized (this) { + isPrepared = false; + } + } + + public void pause() { + if (mediaplayer.isPlaying()) { + mediaplayer.pause(); + } + } + + public void setVolume(float volume) { + mediaplayer.setVolume(volume, volume); + } + + public void setLooping(boolean looping) { + mediaplayer.setLooping(looping); + } + + public void delete() { + if (mediaplayer.isPlaying()) { + mediaplayer.stop(); + } + mediaplayer.release(); + } + + +} \ No newline at end of file diff --git a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Sound.java b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Sound.java new file mode 100644 index 0000000..d5382ba --- /dev/null +++ b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Sound.java @@ -0,0 +1,49 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import android.media.AudioManager; +import android.media.SoundPool; + +import ofenbach.exampleapp.main.MainActivity; +import ofenbach.exampleapp.main.Settings; // change this to your package name + +/* to create simple sounds in your app (e.g. explosions, gunshots). */ +/* @creation: May 2014 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +/* update news 28.4.2018: + + turns off when Settings.sound_on is false + - removed unnecessary comments + */ + + +public class Sound { + + SoundPool soundPool; + + int path; + + + public Sound(int sound_direction) { + soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0); + this.path = soundPool.load(MainActivity.context, sound_direction, 1); + } + + + public void play() { + if (Settings.sound_enabled()) { + soundPool.play(path, 1, 1, 0, 0, 1); + } + } + + + public void setVolume(double procent) { + soundPool.setVolume(path, (float) procent, (float) procent); + } + + + public void delete() { + soundPool.unload(path); + } + +} \ No newline at end of file diff --git a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Sprite.java b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Sprite.java new file mode 100644 index 0000000..63d7115 --- /dev/null +++ b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/framework/Sprite.java @@ -0,0 +1,100 @@ +package ofenbach.exampleapp.framework; // change this to your package name + +import java.util.ArrayList; +import java.util.List; + +/* @creation: 28.4.2018 */ +/* @update: - */ +/* @author: Tim B. Ofenbach */ + +public class Sprite { + + public List images = new ArrayList<>(); // list with pictures + + int current_pic; // current pic to display + double duration; // how long each pic will display / change between the pics (in sec) + double complete_duration; // #pictures*duration + boolean animation; // to start the animation + double timer; // animationtimer + + + public Sprite(int[] pictures, double duration) { + + // parameter update + this.duration = duration; + this.timer = duration; + this.complete_duration = pictures.length * duration; + + // load + for (int i = 0; i screens = new ArrayList<>(); // child list (used by MainView to display the right screen) + + public Screen() { + screens.add(this); // save child + } + + public void repeat() {} // loop 60FPS + + public void load() {} // when the screen starts + + public void touchHold() {} // triggered by touch + + public void touchDown() {} + + public void touchUp() { } + +} diff --git a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/Settings.java b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/Settings.java new file mode 100644 index 0000000..82b13d6 --- /dev/null +++ b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/Settings.java @@ -0,0 +1,30 @@ +package ofenbach.exampleapp.main; // change this to your package name + +/* class with mostly statics, to save your app settings */ +/* @creation: September 2016 */ +/* @update: 28.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class Settings { + + /* Explanation: */ + /* You should also save your app settings (e.g. sound on) here. */ + + public static boolean sound_on = Device.getSavingBool("sound_on"); + + + public static void set_sound_enabled(boolean bool) { + sound_on = bool; + // save + if (bool) { + Device.setSaving("sound_on", 1); + } else { + Device.setSaving("sound_on", 0); + } + } + public static boolean sound_enabled() { + return sound_on; + } + + +} diff --git a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/TouchEvent.java b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/TouchEvent.java new file mode 100644 index 0000000..51cd2a2 --- /dev/null +++ b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/main/TouchEvent.java @@ -0,0 +1,24 @@ +package ofenbach.exampleapp.main; // change this to your package name + +import android.view.MotionEvent; + +/* @creation: March 2018 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class TouchEvent { + + /* Explanation: */ + /* touch-events can be accessed now from everywhere thanks to this class */ + + public static MotionEvent touch_event; // to access coordinations, action-event etc. + + public static int getX() { + return (int) touch_event.getX(); + } + + public static int getY() { + return (int) touch_event.getY(); + } + +} diff --git a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/ExampleScreen.java b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/ExampleScreen.java new file mode 100644 index 0000000..6e6672c --- /dev/null +++ b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/ExampleScreen.java @@ -0,0 +1,110 @@ +package ofenbach.exampleapp.views; + +import ofenbach.exampleapp.framework.Image; +import ofenbach.exampleapp.framework.Sprite; +import ofenbach.exampleapp.main.R; +import ofenbach.exampleapp.main.Screen; + +/* @creation: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +/* update news 28.4.2018: + + added particle animation + + new gravity support used + + automatic positions used + + new touch functions added + */ + + +public class ExampleScreen extends Screen { + + /** FEEL FREE TO EDIT THIS AND PLAY WITH IT! **/ + + // Create Images like this: + Image background; + Image player; + Image floor_1, floor_2, floor_3; + + Sprite particle; + + double gravitytimer; // for the players gravity + double sintimer = 0; // for the ground animation + + + public void load() { + + // Load them like this (put your .png in the res/drawable folder + background = new Image(R.drawable.backdrop); + player = new Image(R.drawable.player); + floor_1 = new Image(R.drawable.floor_1); + floor_2 = new Image(R.drawable.floor_2); + floor_3 = new Image(R.drawable.floor_3); + particle = new Sprite(new int[] {R.drawable.dust_1, R.drawable.dust_2, R.drawable.dust_3, + R.drawable.dust_4, R.drawable.dust_5, R.drawable.dust_6, R.drawable.dust_7}, 0.04); + + // Scale them like this (depending on your wish, use different scale functions, see Image.java) + background.scaleFullscreen(); + player.scaleHalf(); // scaleHalf because the png is twice its normal size (don't ask why) + floor_1.scaleHalf(); + floor_2.scaleHalf(); + floor_3.scaleHalf(); + particle.scaleHalf(); + + // Set your positions like this. Now works with the same resolution (virtual) on every device! + // e.g. player.setX(1920) would be on the far right. + // e.g. player.setY(300) would mean the player is at (300/1080=0.27) 27% screens height. + player.setXtoMiddle(); + player.setYtoMiddle(); + floor_1.setX(0); + floor_1.setY(1080 - floor_1.getHeight() * 0.65); + floor_2.setX(0); + floor_2.setY(floor_1.getY() - floor_2.getHeight()*0.45); + floor_3.setY(floor_2.getY() - floor_3.getHeight() * 0.45); + for (int i = 0; i < particle.images.size(); i ++) { + particle.setX(i,(int) player.getX() + player.getWidth() / 2 - particle.getWidth(i) / 2); + particle.setY(i,(int) (1080 * 0.81)); + } + + // Apply game functions + player.setGravity(9.81); // 9.81 earth gravity + + } + + + public void repeat() { + + // Bounce Check + if (player.y >= floor_2.y - floor_2.getHeight()) { + player.increaseGravity(-3); + particle.startAnimation(); + } + + // Floor animation + floor_1.y = floor_1.getY() + Math.sin(sintimer*0.15)*0.8; // 15% Speed, 0.8x Ausschwenkung + floor_3.y = floor_3.getY() - Math.sin(sintimer*0.15)*0.8; + sintimer += 0.5; + + // Draw your images + background.draw(); + floor_3.draw(); + floor_2.draw(); + floor_1.draw(); + player.draw(); + particle.draw(); + + } + + + /* TOUCH FUNCTIONS */ + public void touchDown() { + player.increaseGravity(1); + } + public void touchUp() { + + } + public void touchHold() { + + } + + +} \ No newline at end of file diff --git a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/GameStart.java b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/GameStart.java new file mode 100644 index 0000000..45bd26b --- /dev/null +++ b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/GameStart.java @@ -0,0 +1,25 @@ +package ofenbach.exampleapp.views; + +/* @creation: 25.4.2018 */ +/* @update: 25.4.2018 */ +/* @author: Tim B. Ofenbach */ + +public class GameStart { + + /** FEEL FREE TO EDIT THIS AND PLAY WITH IT! **/ + + ExampleScreen escreen; // add your costum screens here + + public GameStart() { + + escreen = new ExampleScreen(); // load your own screens here (order important as they will affect there id in Camera.java) + + } + + public void start() { + + escreen.load(); // load/start your own screens here + + } + +} \ No newline at end of file diff --git a/example/ExampleApp/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/example/ExampleApp/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..c7bd21d --- /dev/null +++ b/example/ExampleApp/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/example/ExampleApp/app/src/main/res/drawable/backdrop.png b/example/ExampleApp/app/src/main/res/drawable/backdrop.png new file mode 100644 index 0000000000000000000000000000000000000000..a3e966390535f44dd5d5ee0b04358f124f9dfc51 GIT binary patch literal 4577 zcmd5=TWHf@6h2AQ*;UKj=5$(hPODR@Rdk3lwNo~?iq3h#>4O;OY8BL$QR;@Qjl-9L zHv|z8osT|9iQ>ax$l{BS&c`B73%*I63gQNxm-8oU6VoK?#iB2N$p5$JKj%B&xn-ce zt;J?tWCZ}5r?u%IfJp$LUt3CW=fuT@&j8B(o~E6Ld)|B+J79Bo=9pisIXkfUs`u&C zz_%y-S|4*|;?Bog$zpS&C^tc?SO`UGeF~VZXfX74YaVfiA zAGI_w48YeShKzeQ5_H`+1HXppSovBsC)bd?3*Sp5GGU@cmi3VwuZ;a-F)+lalWYea ztIQ*-D1z*-fFOBk1(h%tTHvO_gH`B~p&B`pk`%ZZ_a4rb_X;;aAt8(WteI#2;DJ5_ z#`U%E41f|eLN_ynj6lp60(8wgQd*T+QCNiNDhKWS|;vg9t$l!x2}JW~BQqxIN6QzQsx3ionk^ z_bDVy$Iawc6KMl#HTzQRuk7mn3SIMg;uy9QT+*-~R90UZZ;4mfbZ689xiIS%#mvND z)EZ@1ox`uxNnnQ7D7&6Bqo?5-s3{S(U4TI;rCfVa#;V+tHn)jN*rYs%?SM1`wa~HI z|D-%CC^}3}{@CF}jRJ0&o}9BNW5bq8K`aM2ed2{8VFQlzu$&%h6x!uqc)lA98(ENF z$SQntpIPhaSRFCGLY(@Z!mCFLd_0I?wt2U0uDdQ{BCRpx<@&{7IkJh2L;C b);C``dCivuQkkAEjv*Ddk`ome%-mf5uwVSA z9cB>ZEX&P2myugf{LqiONF#wtHV%1lhw%11z8?R2`A45Rdo|T({D1c)T7=i2P{N|< zmvxub44X4DCB^J|eEM&y`IbF3nQ`#T;`93hL?&tT8J8aj(qx!@+j`3?9ohRpOLa?J zBT9nv(@M${i&7bqD)o|b^7B(tD)o|!Dho>T^)ho4(^K_;t~WAq%}dTtNiABzR{svD Ok-^i|&t;ucLK6U^A4w+w literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/drawable/dust_2.png b/example/ExampleApp/app/src/main/res/drawable/dust_2.png new file mode 100644 index 0000000000000000000000000000000000000000..146c0bf85f627b1c9c2ecec551f93dcbd75dd76f GIT binary patch literal 269 zcmV+o0rLKdP)AbbW09|kB5F_`%a-#SI<}-ACLZ-qf>R|d{>d?)_ z>7YRqLh!hT`UvI&7Z)9b1 Ts0M%T00000NkvXXu0mjfpK@;b literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/drawable/dust_3.png b/example/ExampleApp/app/src/main/res/drawable/dust_3.png new file mode 100644 index 0000000000000000000000000000000000000000..47cfcebb55bfc78f586bbe6caf7cc97049c9d5ad GIT binary patch literal 284 zcmeAS@N?(olHy`uVBq!ia0vp^IzY_B!3HEHHR8>I)GALG$B>F!$%zik(#lHzlt2Fs zUz3osKv^Nhp8K!>v(5{<&!;Cjel=uvnR89icgM>W*;4O4| zcHjYO1-3<{QQ)ZO18fjv*Ddk`o=6rInTb87DCQ z(+)E*;!#kz7OTT^m}kR+_J;UrJl_P88ctlcUglAH{X@6n7lDfMU%E5Ij6~(G@U`z0 zewG*E!+YO`<+Gul-NK;uOM6^T*u=bZ6qny;*up1Q`;T>D{-2}KuMRkI?A_A1(wRTA zq)_7iu_?l;?+=}6Zd6{rzd6&AH;v=$X}4MJZ88c`CQpH@Jglb@fG vQmL0*R9R4xua}vdn4YQ!3=Sg`*SzHXl+>aXZ1wMe8W}uY{an^LB{Ts5sK#+2 literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/drawable/dust_5.png b/example/ExampleApp/app/src/main/res/drawable/dust_5.png new file mode 100644 index 0000000000000000000000000000000000000000..f04d64049dfdb697afaa34cc12c87a095c5c2e6c GIT binary patch literal 287 zcmeAS@N?(olHy`uVBq!ia0vp^7C_9y!3HGFbL*A@skNRijv*Ddk`o=6rInTbDS!SO zz9u0>;z+}U>PU$;%LGS$&iy))R|Jw8I{3HEP`S4Eusz#F=SO#6Zcm6h5mMn%$?`03 zhJAveWzi=E9hQWI%UjedF5B(>tfE()_->2g(<86?AIdjx5NKQ)Dbdi%QT38V*gf3; zt%U3P`xoB2mfxRv`M%_ao#{`WI7&>ooWORu-|qh*Ek15diTSrGh12+U{e1E5QPKUy z()I3Pax4tx-my&j0iF#&hwGNOMwA5Srt*I9 irl;xwL%_(yH7_|oCADY;Tm3trMg~t;KbLh*2~7YuNpE5R literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/drawable/dust_6.png b/example/ExampleApp/app/src/main/res/drawable/dust_6.png new file mode 100644 index 0000000000000000000000000000000000000000..f9ead5bda50f4a824f335f180b1d43b75e604734 GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^HbBh7!3HGl+V0&4QU#tajv*Ddk`o=6rInTbHD~-6 z)s~QKGdS>+U#v}#E#iXn5q)pAL+KK;41G_?E1S0^DjI|&Pm8GUdG>H&oK^CXk|Q4H z4{s3IVEFV%)T)C|E;{FJn0jhQlGxpNW&O6osaYEYCS6XDo1$x&bl3dR>qLh8_k;I8 zJ^7CXXt!>OYeY$Kep*R+Vo@qXQl(x}PJVt$N~KF!$%ze3y@G=O9k=}N z67Atp=2-B1c59-@0tT@Nj+--zoSb?RQ^@rN95 zwg3DmpmDk-t`Q}{`DrEPiAAXlNtJp@Ir;f1DV2K3MU@35`FfeTiRr0&KzA9LxaKA2 Xr=%9GV5@%z)X3oJ>gTe~DWM4f1*nZJ0Ms<0;N(7#&O~#J}2L|RP8-INgOBk ze{ybeb!p_|?d{K&|NC%v_vDh0*7js)w!LTDF{?kF9dAGHHtu)#%cIT%(e<|Kb;VQy z001zbtJaAB?)}TQ4C9hhX|}c}eI`2D-m~qP)t}Cex1V<#_q+S$QRji^dRz5E0RsR4 ztWdz-i2v#H{eOSIxqkNh=a>5*kN*DV_4S|6-#&fx`zlJkwR)7#OM9|Y>@C|<`qyf2 zv>i3S=xv|$r_t?$y74djSNdc2ao;=MWqWt?%USd3sCmwcYuY>}=Ou5vLjeN-0IX2J z-@bl-^oJL(p8xa0a-GZow8;KOxlj53azCv+S+0fmK31l7woJ7AUfbUmnm@?$N`16U z(Tmn^UcahsU#-8@`e_v2@}un0I{vecdpX{VpVlfh>DO}nMUT5t{^qSu>wN09Z>^nM z=Q*!m*Ty;N_u3Nx6fgh)zzPLin_0;W+}eRpVaPTRy4j9aqxdN4I~KKh^p}w0*64rPtopyy5-a zY9|U9001C^0&Z14*{M~sqcXNxta{s0^9QfOidq}YrdYEQrF<;E$l7kHgro0&lzC&6 zU1!ZpqwHP#B&gNzQNREI0GSoA_WfS3!c3!t4aH?;Y*BC9_GXsZ6kzXK7fSVg)|jPyd&?WGC@p_DnqNfu6^iq6 z$o_6!^E;azX4|#(dTYFmQognGp;bN#7ytm^2ntxsERLGt^(x`BWSl7Bn2b2fp1;w1 zaYLOy|FvHNb`Q00tr8tQ&qZB_0tNs8IFbTB8np_ocTe3Yi#z?Hi?_3BUjV04U(N48+PbM%_1B32PbDEaf@6oZ1ZDo9VB93pm>UtaENH zMy^{OjOv#x<*vH#sBtsf?$PIdYx8jHJf6)iC}02pfE5ZjI`bNp$&FT4 z*4vEM_0i?8vS0Ldvl;ErmeSPDlaB6J>8G+>^_*U1uk)kzOZIZlIv%pj(`T^@3K#$Y zV1)w41bvxNuW~&~#<(lBPed$5X?>s3T2uFa53Z)9b1 Ts0M%T00000NkvXXu0mjfPp(dt literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/drawable/floor_2.png b/example/ExampleApp/app/src/main/res/drawable/floor_2.png new file mode 100644 index 0000000000000000000000000000000000000000..348109574165e7a582b2145a5497a791a558f8e1 GIT binary patch literal 949 zcmeAS@N?(olHy`uVBq!ia0y~yV0-{%t8uUaNf{xJ4h9BhXHOT$kcwMxZ=cT+c9dZF zpv&gySoASLQH;e=|K1zdS1aco5&yvXg|mi*e_td2KiJ73>e3lttvfTt zYIFUhyC(bZtDaTcZEZYr?)%?nFISwZ`26MOnpYQ&ub*GO%fj#a+ooZTwOL+UM?c|T`{(Sqe?4iBK&97|=c)o7;hPbKc z_V0S1zx&*hM_#uJ-&EZ_9s9le`Q4eb)i1x=5@sE8fZ>8W>z)aYZ^BM%H+DZyl`OF< z&QSYj8g*ygj=Lx0pQ{-?+fX~JvNlxm-Gx5!{_;5&r~P|nG*!?nH~sG4F75p;_1@p* zUp=?D^4ZMRe}@0czqiBo?fm*UY2KQQIYocH*M=`$CcD)-FTU#U-N@4x>$2>QmY;ZJ zt;GGGH{=GNr~$*5K*s55bzA?hH#^s3bxtIBs@L6b%d{RY3{i46{PJ_dtABi3gYJgy z^h(wEoD@3sPQbI7}yvXB^U%67(pzS1P}`(fWpG22tzqk(T+p*Z6E$He4iDg0?bvqC9V-A!TD(= z<%vb93`v!GNjdrXDJhkD$wid~CHZ=pxrynidcb^XWa65aoS%|fw1Tbv9Z(~Kr>mdK II;Vst0CXA0FaQ7m literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/drawable/floor_3.png b/example/ExampleApp/app/src/main/res/drawable/floor_3.png new file mode 100644 index 0000000000000000000000000000000000000000..381b51c2634b18f5bf40584f0c21d9bd67bed780 GIT binary patch literal 473 zcmeAS@N?(olHy`uVBq!ia0y~yV0-{%t8uUaNf{xJ4xm7~r;B4q#jUqDw1o~Ch_D9C zSn0GNLMTG)2vdZ>EY*bq5f>7?E}2zko+~`#;2CFU{&K^~63cn_E%)!fmw(&WVdvk@ zbtQYfuN%IqiQ0Xo@LlfR?{@mpciErieUI497R|{p#r%odzn34*{64Aef2GhI)J3IeZyxV6d|84#Led1r2{midl zv^w_v($_am0d3d_vSIf0*EiUgZL{7Qn|FXA;4#~u**A*k$}FqPUnhLx(%;OtDzl>A zuPlw&)wlC}{#Rc2DZiH5rN1nd&)qleRlfFTl~;BFyYEAE-Z{-F`_*iHPyauq21W-4 zW(Fn+1{MPb1)Lm?1O}k81_m~eGIWl>0S1r^BM(Rhg|p%rb5qWgik1uRr-31_TjCl~ z5}cn_Ql40p%8*p4mz0yApOR9kmt0g?P?E2gnVXoNst1faBNNxWq7`iQ?|>Q^ NJYD@<);T3K0RWfnyCDDo literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/drawable/ic_launcher_background.xml b/example/ExampleApp/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..d5fccc5 --- /dev/null +++ b/example/ExampleApp/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ExampleApp/app/src/main/res/drawable/player.png b/example/ExampleApp/app/src/main/res/drawable/player.png new file mode 100644 index 0000000000000000000000000000000000000000..9eadae1b833db6aa475fb35c4c7960028688e5c9 GIT binary patch literal 472 zcmV;}0Vn>6P)dtf0k@F9Ti^W#5R z@oFF>PY77TLKtfA;7J3N`ixirvxjfcX*S50>tKXN&$K~F?d1%-RI6O z;#9S0@1B<^_FNrwA%Gq?8#jNXvQ_AH#Fs%90!y~G)74@_i`+pH0oa}2_204{O#5JLC);0*y7uy1K1D)r;aC9n{Hr6uPahW~>*4d5ydhy~=94}&ia zpoau34siioPDe5{MQ&qnWMy)w27m4V O0000 + + + + \ No newline at end of file diff --git a/example/ExampleApp/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/example/ExampleApp/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/example/ExampleApp/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/example/ExampleApp/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/ExampleApp/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f5908281d070150700378b64a84c7db1f97aa1 GIT binary patch literal 3056 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 axPAxe%7rDusX+w*00006jj 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⁣ zwiG+x#%j}{0gU~J8;<|!B1@-XaB@{KORFwrYg_8rOv({b0EO#DbeQRm;B6_9=mXGf z-x|VL{zd`)#@yN}HkCSJbjbNlE|zL3Wm9Q8HY`sV)}3%pgN>cL^67{Z;PPL(*wT8N zUjXU{@|*hvm}({wsAC=x0^ok0%UAz0;sogW{B!nDqk|JJ5x~4NfTDgP49^zeu`csl?5mY@JdQdISc zFs!E{^grmkLnUk9 zny~m)1vws@5BFI<-0Tuo2JWX(0v`W|t(wg;s--L47WTvTMz-8l#TL^=OJNRS2?_Qj z3AKT+gvbyBi#H*-tJ%tWD|>EV3wy|8qxfzS!5RW;Jpl5*zo&^UBU=fG#2}UvRyNkK zA06Dy9;K1ca@r2T>yThYgI!ont$(G{6q#2QT+00r_x0(b)gsE`lBB?2gr55gq^D3Fi&p%E(p9>U%bv zkg1Jco(RbyTX7FDHOnl7-O@ zI$AaIl?9NJKPm(WiBP`1-#CB1QzU>&hKm)fpa5DKE{2$X0hGz-0uZ?cyTk(YC!Y&| zL=1VrNERSA5NA2jq7FACfX4JfPyj5XXl1yv0>~s;eF7L2$>&oMqeTFT2m$y7FlkON z_yurD1yIOvA;5C6016pyxBznGUt0kJ&k5r#;&>Jow`r)sp9R~PmK~lz$3xH%LT*1U zJdOyABZ3!FvNoR*vN$5ykHS8f`jA4zV+|L}i1C4`B2c{R0;UdYxaU|H)2avz@ z=mEYc|2S<+(B2Tj+FkX+2D+yFI!k9lWMA61DJ{)e;lum$(;O87?vGJJe!KtK04+N_ zI*P~t@dUb>9Xh{dbyl{-ZQ(UMgz7$|QfL5XSPkskt^NgctYC#;4WcZB1@%@wy@2t3 z2z0DI7&%b$*Aw~abe?GxE`ez@+6hOh-6*8fHRV{1os$EL@}uUZeG4h1&Be`98q*7j z=3-v+lhIjfWVo12!<>%V^a6lTgW3+_#W6n|p*~==zOH7z$0{LSZk(Tpd7EaD04hnA zL;#fxS0aD{`5^&D`}>0Uq?byDD-l2=!wm_bLcUl4gc(% za1p|itVANvFF>hghAS07Im1;IK;|b*W)}VDyI;BIp2=K*yu2a)j?B|f<44NI$NbmJ z#dE0>jI$fMr&@>4kN8MLFb4&2O9fEKaQg%(QO$4_1rVQywG^CmBLh#}_7gKW3vd?| z2?1^&KWq8}8I^_S0|)MowU_pw$q@nl@Nkn$z>BQq_KA^9yaR`(R3u{{Ig;cwt z@AJ^{ODQCm^neroM9nKNUAXi9RCK`OsP_LuR0PUR(YZCCX5dNF6VzcoK&=b^r`W?ltt|*F zpkoae%ZT{C1h~EcFui~b7fF`vb<<~j_VquuUA$}QqIKYELPp#;{u?q8Dz}WAG-(3; zjrm$i%7UbyZMM(Y{>!uJ#vNB?R~B{6Htp=>e*<{fQQ5W7V(1coCWlOON!MzZxhum| ztZBQpGR z;~#ur^&PockKdV{Q6R>o`Pl{0x!DEbpZ7y9Y;*ZvE!*gU`V1W3znva{f=?WO5I&>B z&hw6}tjECtaghm5z|C#%M;Yf_*pI^};h}Vl=^r9EN=tVDj86D;C$jIJ?K7VP+00000NkvXXu0mjf D5i!M* literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/example/ExampleApp/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..459ca609d3ae0d3943ab44cdc27feef9256dc6d7 GIT binary patch literal 7098 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 literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/ExampleApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca12fe024be86e868d14e91120a6902f8e88ac6 GIT binary patch literal 6464 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 B0*L?s literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/example/ExampleApp/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..8e19b410a1b15ff180f3dacac19395fe3046cdec GIT binary patch literal 10676 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 literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/example/ExampleApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..4c19a13c239cb67b8a2134ddd5f325db1d2d5bee GIT binary patch literal 15523 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 BIP(Ai literal 0 HcmV?d00001 diff --git a/example/ExampleApp/app/src/main/res/values/colors.xml b/example/ExampleApp/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..3ab3e9c --- /dev/null +++ b/example/ExampleApp/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #3F51B5 + #303F9F + #FF4081 + diff --git a/example/ExampleApp/app/src/main/res/values/strings.xml b/example/ExampleApp/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..ae4d3e2 --- /dev/null +++ b/example/ExampleApp/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + ExampleApp + diff --git a/example/ExampleApp/app/src/main/res/values/styles.xml b/example/ExampleApp/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..ff6c9d2 --- /dev/null +++ b/example/ExampleApp/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/example/ExampleApp/app/src/test/java/ofenbach/exampleapp/main/ExampleUnitTest.java b/example/ExampleApp/app/src/test/java/ofenbach/exampleapp/main/ExampleUnitTest.java new file mode 100644 index 0000000..0b48fea --- /dev/null +++ b/example/ExampleApp/app/src/test/java/ofenbach/exampleapp/main/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package ofenbach.exampleapp.main; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/example/ExampleApp/build.gradle b/example/ExampleApp/build.gradle new file mode 100644 index 0000000..1a3d812 --- /dev/null +++ b/example/ExampleApp/build.gradle @@ -0,0 +1,27 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.1.2' + + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/example/ExampleApp/gradle.properties b/example/ExampleApp/gradle.properties new file mode 100644 index 0000000..743d692 --- /dev/null +++ b/example/ExampleApp/gradle.properties @@ -0,0 +1,13 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true diff --git a/example/ExampleApp/gradle/wrapper/gradle-wrapper.jar b/example/ExampleApp/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7a3265ee94c0ab25cf079ac8ccdf87f41d455d42 GIT binary patch literal 54708 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

_x$+l{{cH8$W#CT literal 0 HcmV?d00001 diff --git a/example/ExampleApp/gradle/wrapper/gradle-wrapper.properties b/example/ExampleApp/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..13e5665 --- /dev/null +++ b/example/ExampleApp/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Apr 24 14:33:05 CEST 2018 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/example/ExampleApp/gradlew b/example/ExampleApp/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/example/ExampleApp/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/example/ExampleApp/gradlew.bat b/example/ExampleApp/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/example/ExampleApp/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/example/ExampleApp/settings.gradle b/example/ExampleApp/settings.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/example/ExampleApp/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/gamestuff/Particle.java b/gamestuff/Particle.java deleted file mode 100644 index f1b946e..0000000 --- a/gamestuff/Particle.java +++ /dev/null @@ -1,30 +0,0 @@ -package ofenbach.exampleapp.main; // change this to your package name - -import android.app.Activity; -import android.os.Bundle; -import android.widget.RelativeLayout; - -/* @creation: April 2018 */ -/* @update: 25.4.2018 */ -/* @author: Tim B. Ofenbach */ - -public class Particle { - - // Leere Liste wo Bilder reinkönnen - - int current_pic; - int duration; // how long each pic will display / change between the pics - int complete_duration; // #pictures*duration - - public Particle(list pictures) { - - } - - public void setPictures(list pictures) {} // setup - - public void startAnimation() {} // trigger to start sprite - - public void draw() {} // put this in your repeat() - - -} \ No newline at end of file diff --git a/main/Camera.java b/main/Camera.java deleted file mode 100644 index 96e1303..0000000 --- a/main/Camera.java +++ /dev/null @@ -1,16 +0,0 @@ -package ofenbach.exampleapp.main; // change this to your package name - -/* to switch screens */ -/* @creation: March 2018 */ -/* @update: 25.4.2018 */ -/* @author: Tim B. Ofenbach */ - -public class Camera { - - public static int currentscreen_id = 0; - - public static void setScreen(int id) { - currentscreen_id = id; - } - -} \ No newline at end of file diff --git a/main/MainActivity.java b/main/MainActivity.java deleted file mode 100644 index 5891534..0000000 --- a/main/MainActivity.java +++ /dev/null @@ -1,33 +0,0 @@ -package ofenbach.exampleapp.main; // change this to your package name - -import android.app.Activity; -import android.os.Bundle; -import android.widget.RelativeLayout; - -/* @creation: February 2014 */ -/* @update: 25.4.2018 */ -/* @author: Tim B. Ofenbach */ - -public class MainActivity extends Activity { - - /** ONLY CHANGE THIS IF YOU KNOW WHAT YOU ARE DOING! **/ - - RelativeLayout layout; - MainView view; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Settings.context = this; - - layout = new RelativeLayout(this); - setContentView(layout); - - view = new MainView(); - layout.addView(view); - - } - - -} \ No newline at end of file diff --git a/main/Settings.java b/main/Settings.java deleted file mode 100644 index db0c32c..0000000 --- a/main/Settings.java +++ /dev/null @@ -1,33 +0,0 @@ -package ofenbach.exampleapp.main; // change this to your package name - -/* class with mostly statics, to save your app data and get device information */ -/* @creation: September 2016 */ -/* @update: 25.4.2018 */ -/* @author: Tim B. Ofenbach */ - -import android.content.Context; - -public class Settings { - - public static Context context; - - public static int screen_height; - public static int screen_width; - - public static boolean sound_on = true; - - - public static Context getContext() { - return context; - } - - public static int getScreenHeight() { - return screen_height; - } - public static int getScreenWidth() { - return screen_width; - } - - - -} \ No newline at end of file From f454c8bffe81cb2ed08d53936fd7a76ae8795e74 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Sat, 28 Apr 2018 16:56:44 +0200 Subject: [PATCH 09/46] Create README.md --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..dc98b29 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# catengine developer 😼 +welcome to the developer-branch + +# new features 💪 ++ gravity support ✅ ++ save support ✅ ++ particle support ✅ ++ automatic positions (screen independent) ✅ ++ better touch functions ✅ ++ reduce code (make it even simpler to use) ⚒️ + +# example 👀 +The new example has all the features that are available! + +# guide 📖 +1. Download the engine folder. +2. Import the folder into your app project (@src). +3. Fix the imports depending on your app/package name. +4. Create GameStart.java to load your screens. +6. Your app now runs catengine! + +# donations 💸 +If you feel like supporting my work, feel free to donate: + +![alt text](https://steemit-production-imageproxy-upload.s3.amazonaws.com/DQmc8NTQJp8vubgKHs2DgFiRx9ie2BZRrpzfj99Nh6PnUn9) 31hwi7KqnCo2L4mmtm7FeQuarggVxMiRy8 +![alt text](https://steemit-production-imageproxy-upload.s3.amazonaws.com/DQmUJCKengMc25qYjBUKWodBUkXHb6m9VU47WnSTtwk46Qs) LVtnsswBGixXtBRm6a3nJths3QfABmSDZZ +![alt text](https://steemit-production-imageproxy-upload.s3.amazonaws.com/DQmdnnCcukhq9CAri1LaY9NGERrCNdexdwahAnLo8YFZ52K) 0xE6af1aaB8b26c88b36Af9bd0Fc16ced85EdB13d7 + +Thank you! :) + +# contact ✉️ +Questions? Email me: tim@ofenba.ch From 918f0246b010ecf6f1b438a9189ad785dff436db Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Sat, 28 Apr 2018 17:12:43 +0200 Subject: [PATCH 10/46] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dc98b29..5f6e811 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # catengine developer 😼 -welcome to the developer-branch +welcome to the developer-branch +full changelog: engine/main/MainActivity.java # new features 💪 + gravity support ✅ From 673de13543a850d95e5d6c376594bba269cbf02a Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Sat, 28 Apr 2018 17:27:25 +0200 Subject: [PATCH 11/46] added #planned features --- README.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5f6e811..82744f4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# catengine developer 😼 +# catengine developer edition 😼 welcome to the developer-branch -full changelog: engine/main/MainActivity.java +full changelog: engine/main/MainActivity.java # new features 💪 + gravity support ✅ @@ -18,7 +18,14 @@ The new example has all the features that are available! 2. Import the folder into your app project (@src). 3. Fix the imports depending on your app/package name. 4. Create GameStart.java to load your screens. -6. Your app now runs catengine! +6. Your app now runs catengine developer edition! + +# planned features 🤔 ++ GUI version 😍 + + simple drag&drop to create objects 🖱️ + + simple kid-friendly coding 👶 ++ even better particles ++ even simpler to use (code version 🤓) # donations 💸 If you feel like supporting my work, feel free to donate: @@ -27,7 +34,7 @@ If you feel like supporting my work, feel free to donate: ![alt text](https://steemit-production-imageproxy-upload.s3.amazonaws.com/DQmUJCKengMc25qYjBUKWodBUkXHb6m9VU47WnSTtwk46Qs) LVtnsswBGixXtBRm6a3nJths3QfABmSDZZ ![alt text](https://steemit-production-imageproxy-upload.s3.amazonaws.com/DQmdnnCcukhq9CAri1LaY9NGERrCNdexdwahAnLo8YFZ52K) 0xE6af1aaB8b26c88b36Af9bd0Fc16ced85EdB13d7 -Thank you! :) +Thank you! ❤️ # contact ✉️ Questions? Email me: tim@ofenba.ch From c4eff12cac7990567c379bb2dfb439ae24e5f227 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Sat, 28 Apr 2018 17:27:37 +0200 Subject: [PATCH 12/46] added #planned features added emojis From 09ea1589f3e87a300001d7427fc82f55686289fe Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Wed, 2 May 2018 20:44:41 +0200 Subject: [PATCH 13/46] added #todo --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 82744f4..22f1df7 100644 --- a/README.md +++ b/README.md @@ -38,3 +38,10 @@ Thank you! ❤️ # contact ✉️ Questions? Email me: tim@ofenba.ch + +# todo ++ add jetpack to example ++ add menu ++ add more animation ++ decide between underscore or camelCase ++ improve code From 691b26f695408308ba22ee1aac65d182f78bef85 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Wed, 2 May 2018 20:54:47 +0200 Subject: [PATCH 14/46] improved text added text to #catengine changed #new features changed #planned features removed #todo --- README.md | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 22f1df7..ed6b83c 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,17 @@ # catengine developer edition 😼 -welcome to the developer-branch -full changelog: engine/main/MainActivity.java +Welcome to the developer-branch! +From here you can check out some of the new features that aren't available yet. +It is not recommenced to use this version in your release apps, as there will be bugs. + +See full changelog: engine/main/MainActivity.java # new features 💪 + gravity support ✅ + save support ✅ -+ particle support ✅ -+ automatic positions (screen independent) ✅ ++ sprite support ✅ ++ automatic positions (resolution independent) ✅ + better touch functions ✅ -+ reduce code (make it even simpler to use) ⚒️ ++ IDE Documentation support ⚒️ # example 👀 The new example has all the features that are available! @@ -22,10 +25,9 @@ The new example has all the features that are available! # planned features 🤔 + GUI version 😍 - + simple drag&drop to create objects 🖱️ + + simple drag&drop to create apps 🖱️ + simple kid-friendly coding 👶 -+ even better particles -+ even simpler to use (code version 🤓) ++ new effects (e.g. particles, explosions, fire) # donations 💸 If you feel like supporting my work, feel free to donate: @@ -38,10 +40,3 @@ Thank you! ❤️ # contact ✉️ Questions? Email me: tim@ofenba.ch - -# todo -+ add jetpack to example -+ add menu -+ add more animation -+ decide between underscore or camelCase -+ improve code From 8d035d7038e0b76e068131a8e676cf5cdb4b8043 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Thu, 3 May 2018 00:23:20 +0200 Subject: [PATCH 15/46] Update README.md added #pro version --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index ed6b83c..402d1b8 100644 --- a/README.md +++ b/README.md @@ -38,5 +38,13 @@ If you feel like supporting my work, feel free to donate: Thank you! ❤️ +#pro version 🏎️ +Another way to support me, is to buy the pro version for 5$ ++ no watermark 🚱 ++ active development 🖥️ ++ sprite support 🖼️ ++ save support 💾 ++ complete engine documentation 📚 + # contact ✉️ Questions? Email me: tim@ofenba.ch From 5765112562ac865dd87f09086968bdeee1ce9438 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Thu, 3 May 2018 00:23:40 +0200 Subject: [PATCH 16/46] Update README.md fixed format --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 402d1b8..024e96b 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ If you feel like supporting my work, feel free to donate: Thank you! ❤️ -#pro version 🏎️ +# pro version 🏎️ Another way to support me, is to buy the pro version for 5$ + no watermark 🚱 + active development 🖥️ From d13f0ea2326a2d1a1f2d0672a55db60de953462e Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Thu, 3 May 2018 00:29:24 +0200 Subject: [PATCH 17/46] Create README.md --- engine/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 engine/README.md diff --git a/engine/README.md b/engine/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/engine/README.md @@ -0,0 +1 @@ + From 8f0635f45e67131fe90109b8d386adf2dd549693 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Thu, 3 May 2018 00:32:36 +0200 Subject: [PATCH 18/46] Update README.md --- engine/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/engine/README.md b/engine/README.md index 8b13789..a18d16b 100644 --- a/engine/README.md +++ b/engine/README.md @@ -1 +1,21 @@ +# Image.java +draw() +scale() +setAngle(int) +setAlpha(int) +getAngleTo(image): int +collidesWith(image): boolean +# Button.java +isPressed(): boolean + +# Music.java +play() +pause() +stop() +delte() + +# Sound.java +play() +stop() +delete() From ef160073650277352fa7353f0731cd6ad6484a92 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:42:54 +0200 Subject: [PATCH 19/46] Update Image.java improved comments, format --- engine/framework/Image.java | 97 ++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 55 deletions(-) diff --git a/engine/framework/Image.java b/engine/framework/Image.java index e7f3801..d3aa49c 100644 --- a/engine/framework/Image.java +++ b/engine/framework/Image.java @@ -22,28 +22,26 @@ public class Image { - // Bitmap & Path + // File Bitmap bitmap; int path; - // Position & Angle - public double x = 0; // width: 1920 - public double y = 0; // height: 1080 + // position & angle + public double x, y; int angle; - // Matrix & Paint (rotation & transparency) + // rotation & transparency Matrix m; Paint p; // Gravity - public double gravity_factor; - public double gravity_timer; + public double gravity_factor, gravity_timer; /* CONSTRUCTOR */ public Image(int path) { - this.path = path; // parameter update + this.path = path; m = new Matrix(); p = new Paint(); @@ -59,59 +57,48 @@ public Image(int path) { /* DRAW */ public void draw() { - // Anglesettings - m.reset(); - m.postRotate(angle, bitmap.getWidth() / 2, bitmap.getHeight() / 2); - m.postTranslate((float) (x/1920)*Device.get_screen_width(), (float) (y/1080)*Device.get_screen_height()); + // Anglesettings + m.reset(); + m.postRotate(angle, bitmap.getWidth() / 2, bitmap.getHeight() / 2); + m.postTranslate((float) (x/1920)*Device.get_screen_width(), (float) (y/1080)*Device.get_screen_height()); - // Gravity + // Gravity if (gravity_factor != 0) { this.applyGravity(); } - // Draw + // Draw MainView.global_canvas.drawBitmap(bitmap, m, p); } /* SCALING */ - public void scale(double factor) { + public void scale() { // Calculation - double relativewidth = 1080 / (factor * bitmap.getWidth()); double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); - double width = Device.get_screen_width() / relativewidth; - double height = ratio * width; + double real_width = Device.get_screen_width() * ((double) bitmap.getWidth() / 480); + double real_height = real_width * ratio;; // Scaling - bitmap = Bitmap.createScaledBitmap(bitmap, (int) width, (int) height, false); + bitmap = Bitmap.createScaledBitmap(bitmap, (int) real_width, (int) real_height, false); } - public void scaleFullscreen() { - bitmap = Bitmap.createScaledBitmap(bitmap, Device.get_screen_width(), Device.get_screen_height(), false); - } - public void scale() { + public void scale(double factor) { // Calculation + double relative_width = 1080 / (factor * bitmap.getWidth()); double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); - double realwidth = Device.get_screen_width() * ((double) bitmap.getWidth()*2 / 480); - double realheight = realwidth * ratio;; + double width = Device.get_screen_width() / relative_width; + double height = ratio * width; // Scaling - bitmap = Bitmap.createScaledBitmap(bitmap, (int) realwidth, (int) realheight, false); + bitmap = Bitmap.createScaledBitmap(bitmap, (int) width, (int) height, false); } - public void scaleHalf() { - - // Calculation - double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); - double realwidth = Device.get_screen_width() * ((double) bitmap.getWidth() / 480); - double realheight = realwidth * ratio;; - - // Scaling - bitmap = Bitmap.createScaledBitmap(bitmap, (int) realwidth, (int) realheight, false); - + public void scaleFullscreen() { + bitmap = Bitmap.createScaledBitmap(bitmap, Device.get_screen_width(), Device.get_screen_height(), false); } @@ -119,6 +106,10 @@ public void scaleHalf() { public void setAlpha(int alpha) { p.setAlpha(alpha); } + public void setTransparency(double percent) { + int real_value = (int) percent * 255; + p.setAlpha(real_value); + } public void move(double distance) { // Calculation @@ -148,7 +139,7 @@ public void setYtoMiddle() { //this.y = Device.get_screen_height() / 2 - this.getHeight() / 2; // old way: relative but still absolut y = 1080 / 2 - getHeight() / 2; // new way: relative/automatic } - public void setRotation(double angle) { + public void setAngle(double angle) { this.angle = (int) angle; m.reset(); m.postRotate((int) angle, bitmap.getWidth() / 2, bitmap.getHeight() / 2); @@ -212,17 +203,27 @@ public double getAngleTo(Image image) { public int getAlpha() { return p.getAlpha(); } - public Bitmap getBitMap() { + public Bitmap getBitmap() { return bitmap; } + public boolean isInScreen() { + if (this.x > -this.getWidth() && this.x < Device.get_screen_width()) { + if (this.y > -this.getHeight() && this.y < Device.get_screen_height()) { + return true; + } else { + return false; + } + } else { + return false; + } + } /* COLLISION */ public boolean collidesWith(Image image) { - // See CollisionDetection.java return CollisionDetection.isCollisionDetected(bitmap, (int) x, (int) y, image.bitmap, (int) image.x, (int) image.y); - + } @@ -237,20 +238,6 @@ public void applyGravity() { // updates gravity movement (put this in your rep public void increaseGravity(int increase) { this.gravity_timer += increase; } - - - /* ON SCREEN? */ - public boolean isInScreen() { - if (this.x > -this.getWidth() && this.x < Device.get_screen_width()) { - if (this.y > -this.getHeight() && this.y < Device.get_screen_height()) { - return true; - } else { - return false; - } - } else { - return false; - } - } /* DELETE */ @@ -259,4 +246,4 @@ public void delete() { } -} \ No newline at end of file +} From 99e2fa3e2c29fd5ad0e21c9fb38efd95f5ad3469 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:43:55 +0200 Subject: [PATCH 20/46] Update Sound.java improved format --- engine/framework/Sound.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/engine/framework/Sound.java b/engine/framework/Sound.java index d5382ba..ee0d929 100644 --- a/engine/framework/Sound.java +++ b/engine/framework/Sound.java @@ -3,7 +3,7 @@ import android.media.AudioManager; import android.media.SoundPool; -import ofenbach.exampleapp.main.MainActivity; +import ofenbach.exampleapp.main.MainActivity; // change this to your package name import ofenbach.exampleapp.main.Settings; // change this to your package name /* to create simple sounds in your app (e.g. explosions, gunshots). */ @@ -20,30 +20,25 @@ public class Sound { SoundPool soundPool; - int path; - public Sound(int sound_direction) { soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0); this.path = soundPool.load(MainActivity.context, sound_direction, 1); } - public void play() { if (Settings.sound_enabled()) { soundPool.play(path, 1, 1, 0, 0, 1); } } - public void setVolume(double procent) { soundPool.setVolume(path, (float) procent, (float) procent); } - public void delete() { soundPool.unload(path); } -} \ No newline at end of file +} From fd137b817930d984e50f51d886cdec8ec6f2e16d Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:44:25 +0200 Subject: [PATCH 21/46] Update Music.java improved format --- engine/framework/Music.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/engine/framework/Music.java b/engine/framework/Music.java index e01da8f..ed78179 100644 --- a/engine/framework/Music.java +++ b/engine/framework/Music.java @@ -18,13 +18,13 @@ public class Music { MediaPlayer mediaplayer; - int path; + boolean isPrepared; public Music(int path) { - this.path = path; // update path + this.path = path; mediaplayer = new MediaPlayer(); mediaplayer = MediaPlayer.create(MainActivity.context, path); // load music @@ -65,5 +65,4 @@ public void delete() { mediaplayer.release(); } - -} \ No newline at end of file +} From cfe40b3381524613458de80e78c50f349f953648 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:45:49 +0200 Subject: [PATCH 22/46] Update Sprite.java improved format --- engine/framework/Sprite.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/engine/framework/Sprite.java b/engine/framework/Sprite.java index 63d7115..e697f5a 100644 --- a/engine/framework/Sprite.java +++ b/engine/framework/Sprite.java @@ -17,7 +17,6 @@ public class Sprite { boolean animation; // to start the animation double timer; // animationtimer - public Sprite(int[] pictures, double duration) { // parameter update @@ -32,19 +31,17 @@ public Sprite(int[] pictures, double duration) { } - public void startAnimation() { this.animation = true; } - public void draw() { // put this in your repeat() if (animation) { - + if (timer < duration) { - timer += 0.01666666666; + timer += 0.01666666666; // 60times = 1sec } else { @@ -74,7 +71,6 @@ public void setY(int id, int y) { images.get(id).setY(y); } - /* GET FUNCTIONS */ public int getWidth(int id) { return images.get(id).getWidth(); @@ -83,7 +79,6 @@ public int getHeight(int id) { return images.get(id).getHeight(); } - /* SCALE */ public void scaleHalf() { for (int i = 0; i Date: Tue, 8 May 2018 01:46:46 +0200 Subject: [PATCH 23/46] Update Camera.java improved code --- engine/main/Camera.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/engine/main/Camera.java b/engine/main/Camera.java index 0450204..ea861c4 100644 --- a/engine/main/Camera.java +++ b/engine/main/Camera.java @@ -5,16 +5,16 @@ /* @update: 26.4.2018 */ /* @author: Tim B. Ofenbach */ -public class Camera { +/* Explanation: */ +/* only saves which screen_id to display */ +/* MainView displays Screen.children[Camera.currentscreen_id] */ - /* Explanation: */ - /* only saves which screen_id to display */ - /* MainView displays Screen.children[Camera.currentscreen_id] */ +public class Camera { - public static int currentscreen_id = 0; // current screen to display + public static int current_screen_id = 0; // current screen to display public static void setScreen(int id) { - currentscreen_id = id; // switch current screen to display + current_screen_id = id; // switch current screen to display } -} \ No newline at end of file +} From 2fc723633bf1db03b33753e816855f7efc1373d1 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:47:42 +0200 Subject: [PATCH 24/46] Update MainView.java improved code --- engine/main/MainView.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/engine/main/MainView.java b/engine/main/MainView.java index b1c710e..2feea50 100644 --- a/engine/main/MainView.java +++ b/engine/main/MainView.java @@ -11,13 +11,12 @@ /* @update: 28.4.2018 */ /* @author: Tim B. Ofenbach */ -public class MainView extends View { +/* Explanation: */ +/* This Class is the real screen thats being displayed by android os. */ +/* It selects the current screen (saved in Camera) and repeats it's repeat() method. */ - /** ONLY CHANGE THIS IF YOU KNOW WHAT YOU ARE DOING! **/ - - /* Explanation: */ - /* This Class is the real screen thats being displayed by android os. */ - /* It selects the current screen (saved in Camera) and repeats it's repeat() method. */ +/** DO NOT CHANGE THIS UNLESS YOU KNOW WHAT YOU ARE DOING! **/ +public class MainView extends View { public static Canvas global_canvas; // used by Image.java to draw @@ -44,10 +43,10 @@ public void onDraw(Canvas c) { gamestart.start(); } - Screen.screens.get(Camera.currentscreen_id).repeat(); // display current screen + Screen.screens.get(Camera.current_screen_id).repeat(); // display current screen if (touch_hold) { - Screen.screens.get(Camera.currentscreen_id).touchHold(); // trigger touch function in the right screen + Screen.screens.get(Camera.current_screen_id).touchHold(); // trigger touch function in the right screen } invalidate(); // repeat this method @@ -61,12 +60,12 @@ public boolean onTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { // finger starts touching the screen touch_hold = true; - Screen.screens.get(Camera.currentscreen_id).touchDown(); + Screen.screens.get(Camera.current_screen_id).touchDown(); } if (ev.getAction() == MotionEvent.ACTION_UP) { // finger loses touch touch_hold = false; - Screen.screens.get(Camera.currentscreen_id).touchUp(); + Screen.screens.get(Camera.current_screen_id).touchUp(); } return true; From bef8c3796281125146bf11775e47675f61bd4cd3 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:48:58 +0200 Subject: [PATCH 25/46] Update Screen.java improved code --- engine/main/Screen.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/engine/main/Screen.java b/engine/main/Screen.java index 90618ca..322108a 100644 --- a/engine/main/Screen.java +++ b/engine/main/Screen.java @@ -8,12 +8,12 @@ /* @update: 25.4.2018 */ /* @author: Tim B. Ofenbach */ +/* Explanation: */ +/* acts as a superclass for your screens. */ +/* here are all the screens which were created stored */ +/* MainView displays the right screen (id stored at Camera) via this list */ + public class Screen { - - /* Explanation: */ - /* acts as a superclass for your screens. */ - /* here are all the screens which were created stored */ - /* MainView displays the right screen (id stored at Camera) via this list */ public static List screens = new ArrayList<>(); // child list (used by MainView to display the right screen) @@ -21,14 +21,11 @@ public Screen() { screens.add(this); // save child } + /* @override */ public void repeat() {} // loop 60FPS - public void load() {} // when the screen starts - public void touchHold() {} // triggered by touch - public void touchDown() {} - public void touchUp() { } } From d6f0f31aeab785356f8f82f54afa6a841a76f0e3 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:50:19 +0200 Subject: [PATCH 26/46] Update Settings.java improved code --- engine/main/Settings.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/engine/main/Settings.java b/engine/main/Settings.java index 82b13d6..c25b911 100644 --- a/engine/main/Settings.java +++ b/engine/main/Settings.java @@ -5,26 +5,19 @@ /* @update: 28.4.2018 */ /* @author: Tim B. Ofenbach */ -public class Settings { +/* Explanation: */ +/* You should also save your app settings (e.g. sound on) here. */ - /* Explanation: */ - /* You should also save your app settings (e.g. sound on) here. */ +public class Settings { public static boolean sound_on = Device.getSavingBool("sound_on"); - - public static void set_sound_enabled(boolean bool) { - sound_on = bool; - // save - if (bool) { - Device.setSaving("sound_on", 1); - } else { - Device.setSaving("sound_on", 0); - } + public static void set_sound_enabled(boolean sound_on) { + this.sound_on = sound_on; + Device.setSavingBool("sound_on", sound_on); } public static boolean sound_enabled() { return sound_on; } - } From 12d4da045fe53d0721a3d23a11578c5c8a510294 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:51:11 +0200 Subject: [PATCH 27/46] Update Device.java improved code changed function names --- engine/main/Device.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/engine/main/Device.java b/engine/main/Device.java index 06d572a..0f819cc 100644 --- a/engine/main/Device.java +++ b/engine/main/Device.java @@ -8,8 +8,7 @@ public class Device { - public static int screen_height; - public static int screen_width; + public static int screen_height, screen_width; /* Device specs */ public static int get_screen_width() { @@ -19,22 +18,21 @@ public static int get_screen_height() { return screen_height; } - /* Save functions */ - public static void setSaving(String file_name, int value) { + public static void setSavingInt(String file_name, int value) { SharedPreferences file = MainActivity.context.getSharedPreferences(file_name, 0); SharedPreferences.Editor editor = file.edit(); editor.putInt(file_name, value); editor.commit(); } - public static void setSaving(String file_name, boolean value) { + public static void setSavingBool(String file_name, boolean value) { SharedPreferences file = MainActivity.context.getSharedPreferences(file_name, 0); SharedPreferences.Editor editor = file.edit(); if (value) { editor.putInt(file_name, 1); } else { editor.putInt(file_name, 0); } editor.commit(); } - public static int getSaving(String file_name) { + public static int getSavingInt(String file_name) { SharedPreferences file = MainActivity.context.getSharedPreferences(file_name, 0); return file.getInt(file_name, 0); } @@ -47,5 +45,4 @@ public static boolean getSavingBool(String file_name) { } } - -} \ No newline at end of file +} From 0ca9f5ea7bfb0965dcd4859cbb530afd2ebba10e Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:52:01 +0200 Subject: [PATCH 28/46] Update MainActivity.java improved format --- engine/main/MainActivity.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/engine/main/MainActivity.java b/engine/main/MainActivity.java index 456719d..91a2e8c 100644 --- a/engine/main/MainActivity.java +++ b/engine/main/MainActivity.java @@ -33,13 +33,12 @@ */ -public class MainActivity extends Activity { +/* Explanation: */ +/* The app starts here. */ +/* From here, the MainView starts and selects the screen to display */ - /** ONLY CHANGE THIS IF YOU KNOW WHAT YOU ARE DOING! **/ - - /* Explanation: */ - /* The app starts here. */ - /* From here, the MainView starts and selects the screen to display */ +/** DO NOT CHANGE THIS UNLESS YOU KNOW WHAT YOU ARE DOING! **/ +public class MainActivity extends Activity { RelativeLayout layout; MainView view; @@ -60,5 +59,4 @@ protected void onCreate(Bundle savedInstanceState) { } - -} \ No newline at end of file +} From 5da276325f3b0f33190ce560f406f5859054f335 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:52:32 +0200 Subject: [PATCH 29/46] Update TouchEvent.java improved format --- engine/main/TouchEvent.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/main/TouchEvent.java b/engine/main/TouchEvent.java index 51cd2a2..19e758c 100644 --- a/engine/main/TouchEvent.java +++ b/engine/main/TouchEvent.java @@ -6,10 +6,10 @@ /* @update: 25.4.2018 */ /* @author: Tim B. Ofenbach */ +/* Explanation: */ +/* touch-events can be accessed now from everywhere thanks to this class */ + public class TouchEvent { - - /* Explanation: */ - /* touch-events can be accessed now from everywhere thanks to this class */ public static MotionEvent touch_event; // to access coordinations, action-event etc. From 54e87a64d83030be5a1b6c1e3356bab6a057fb1b Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:55:19 +0200 Subject: [PATCH 30/46] Update README.md improved format --- engine/README.md | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/engine/README.md b/engine/README.md index a18d16b..2eeda89 100644 --- a/engine/README.md +++ b/engine/README.md @@ -1,21 +1,27 @@ # Image.java -draw() -scale() -setAngle(int) -setAlpha(int) -getAngleTo(image): int -collidesWith(image): boolean +Useful functions: + draw() + scale() + scale(double) + scaleFullscreen() + setAngle(int) + setAlpha(int) + getAngleTo(image): int + collidesWith(image): boolean # Button.java -isPressed(): boolean +Same as Image.java but can register touch. + isPressed(): boolean # Music.java -play() -pause() -stop() -delte() +Basic functions: + play() + pause() + stop() + delete() # Sound.java -play() -stop() -delete() +Basic functions: + play() + stop() + delete() From 3676594503786c5a8adc93eca0735c72d16e26ef Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:55:34 +0200 Subject: [PATCH 31/46] Update README.md --- engine/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/README.md b/engine/README.md index 2eeda89..9cef037 100644 --- a/engine/README.md +++ b/engine/README.md @@ -1,7 +1,7 @@ # Image.java Useful functions: draw() - scale() + scale() scale(double) scaleFullscreen() setAngle(int) From 0ddbac7e70d35e3845cc720541b108960922c80f Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 01:59:47 +0200 Subject: [PATCH 32/46] Update README.md added #Device.java --- engine/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/engine/README.md b/engine/README.md index 9cef037..e401298 100644 --- a/engine/README.md +++ b/engine/README.md @@ -25,3 +25,11 @@ Basic functions: play() stop() delete() + +# Device.java ++ get_screen_width(): int ++ get_screen_height(): int ++ setSavingInt(String, int) <- for saving numbers onto the device ++ setSavingBool(bool) <- for saving bool values onto the device ++ getSavingInt(String): int <- get int value of file (filename: parameter string) ++ getSavingBool(String): bool <-same with bool From d61b2b7dfee6aac5a725cdb62efa9a45244c6b5f Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 02:01:07 +0200 Subject: [PATCH 33/46] Update Image.java added setGravityTimer(int) --- engine/framework/Image.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engine/framework/Image.java b/engine/framework/Image.java index d3aa49c..4d9f7bc 100644 --- a/engine/framework/Image.java +++ b/engine/framework/Image.java @@ -238,6 +238,9 @@ public void applyGravity() { // updates gravity movement (put this in your rep public void increaseGravity(int increase) { this.gravity_timer += increase; } + public void setGravityTimer(int value) { + this.gravity_timer = value; + } /* DELETE */ From cfb38295ac7857e9244791b9798b6925f5c34cee Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 02:02:30 +0200 Subject: [PATCH 34/46] Update README.md updated #new features put #guide higher --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 024e96b..7d17dc7 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,12 @@ It is not recommenced to use this version in your release apps, as there will be See full changelog: engine/main/MainActivity.java # new features 💪 +The update is done! I am working on bugfixes, stabilization etc. for the release. + gravity support ✅ + save support ✅ + sprite support ✅ + automatic positions (resolution independent) ✅ + better touch functions ✅ -+ IDE Documentation support ⚒️ - -# example 👀 -The new example has all the features that are available! # guide 📖 1. Download the engine folder. @@ -23,6 +20,9 @@ The new example has all the features that are available! 4. Create GameStart.java to load your screens. 6. Your app now runs catengine developer edition! +# example 👀 +The new example has all the features that are available! + # planned features 🤔 + GUI version 😍 + simple drag&drop to create apps 🖱️ From 393e7281f1a6cd47a1970369034d158514ff0d40 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 02:04:04 +0200 Subject: [PATCH 35/46] Update ExampleScreen.java --- .../exampleapp/views/ExampleScreen.java | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/ExampleScreen.java b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/ExampleScreen.java index 6e6672c..b0bfa3c 100644 --- a/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/ExampleScreen.java +++ b/example/ExampleApp/app/src/main/java/ofenbach/exampleapp/views/ExampleScreen.java @@ -27,9 +27,7 @@ public class ExampleScreen extends Screen { Sprite particle; - double gravitytimer; // for the players gravity - double sintimer = 0; // for the ground animation - + double gravitytimer, sintimer; // for the players gravity public void load() { @@ -44,15 +42,13 @@ public void load() { // Scale them like this (depending on your wish, use different scale functions, see Image.java) background.scaleFullscreen(); - player.scaleHalf(); // scaleHalf because the png is twice its normal size (don't ask why) + player.scaleHalf(); floor_1.scaleHalf(); floor_2.scaleHalf(); floor_3.scaleHalf(); particle.scaleHalf(); // Set your positions like this. Now works with the same resolution (virtual) on every device! - // e.g. player.setX(1920) would be on the far right. - // e.g. player.setY(300) would mean the player is at (300/1080=0.27) 27% screens height. player.setXtoMiddle(); player.setYtoMiddle(); floor_1.setX(0); @@ -75,7 +71,7 @@ public void repeat() { // Bounce Check if (player.y >= floor_2.y - floor_2.getHeight()) { - player.increaseGravity(-3); + player.setGravityTimer(-3); particle.startAnimation(); } @@ -99,12 +95,7 @@ public void repeat() { public void touchDown() { player.increaseGravity(1); } - public void touchUp() { - - } - public void touchHold() { - - } - + public void touchUp() {} + public void touchHold() {} -} \ No newline at end of file +} From bacd3adcf20399d6f39d71bd38493708916bf685 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Tue, 8 May 2018 02:05:11 +0200 Subject: [PATCH 36/46] Update README.md added not available hint @#pro version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d17dc7..46c46db 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ If you feel like supporting my work, feel free to donate: Thank you! ❤️ -# pro version 🏎️ +# pro version (NOT AVAILABLE ATM) 🏎️ Another way to support me, is to buy the pro version for 5$ + no watermark 🚱 + active development 🖥️ From 3cc1b3218d10de3c8ce5cc263afb4e3c2fc81351 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Mon, 14 May 2018 18:25:58 +0200 Subject: [PATCH 37/46] Update Camera.java improved explanation --- engine/main/Camera.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/main/Camera.java b/engine/main/Camera.java index ea861c4..92a1b66 100644 --- a/engine/main/Camera.java +++ b/engine/main/Camera.java @@ -6,7 +6,7 @@ /* @author: Tim B. Ofenbach */ /* Explanation: */ -/* only saves which screen_id to display */ +/* Saves which screen to display. */ /* MainView displays Screen.children[Camera.currentscreen_id] */ public class Camera { From d51d400af50fbb622137889ca85bb08552ed9adb Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Mon, 14 May 2018 19:56:14 +0200 Subject: [PATCH 38/46] added License --- License.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 License.txt diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..9f3dec6 --- /dev/null +++ b/License.txt @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2018 Tim Ofenbach + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +Selling copies of the Software is forbidden! + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE From 2dad84593f26f8a354401ae542b2972393c62da2 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Mon, 14 May 2018 20:07:49 +0200 Subject: [PATCH 39/46] added codestyle explanation --- CODESTYLE.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 CODESTYLE.md diff --git a/CODESTYLE.md b/CODESTYLE.md new file mode 100644 index 0000000..5b31efa --- /dev/null +++ b/CODESTYLE.md @@ -0,0 +1,65 @@ +# Code Style + +## Naming conventions + +* File names: PascalCase +* Folder names: PascalCase +* Class names: PascalCase +* Functions: camelCase +* Local variables: underscore_case +* Constants: SCREAMING_SNAKE_CASE + +## Class Style + +```Java +class Image { + + // Class vars + int example_int, example_int2; + boolean example_bool; + + public Image() {} + + /* DRAW */ + public void draw() {} + + /* SCALING */ + public void scale() {} + public void scale(double factor) {} + + /* EXAMPLE GROUP */ + public void exampleFunc() {} + public void exampleFunc2() { + + // Calculate something + calculate(); + calculateAgain(); + + // next group + doSomething(); + again(); + + } + + ... + +} +``` + +* Public functions and members at top, protected in middle, private at bottom +* Class variables at top, then constructor then special functions, divided into groups. +* Often, code is divided by comments. + +## Functions + +* Function names should be descriptive of what they do and should be a verb ("doing word") +* Functions which return "bool" should be a question eg + +```Java +boolean isXGreaterThan5 (int x) { + return x > 5; +} +``` + +## Enums +* Use enum class, not regular enums! From 73b75c76193eda66614357753f809b12e4935f9f Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Mon, 14 May 2018 20:10:40 +0200 Subject: [PATCH 40/46] added new feature --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 46c46db..6a760d1 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ The update is done! I am working on bugfixes, stabilization etc. for the release + sprite support ✅ + automatic positions (resolution independent) ✅ + better touch functions ✅ ++ improved github doc ✅ # guide 📖 1. Download the engine folder. From 29157b4e09bc80627a5c79d2ecad34874cfbb0df Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Mon, 14 May 2018 20:12:59 +0200 Subject: [PATCH 41/46] added installation guide added installation guide improved format --- engine/README.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/engine/README.md b/engine/README.md index e401298..f663571 100644 --- a/engine/README.md +++ b/engine/README.md @@ -1,4 +1,13 @@ -# Image.java +# Installation +1) Download main and framework folder. +2) Import them to your src folder in your android studio project. +3) Fix the imports depending on your package names (android studio will help you). +4) Create GameStart.java and your own screens. +5) Your app runs catengine. + +# Documentation + +## Image.java Useful functions: draw() scale() @@ -9,24 +18,24 @@ Useful functions: getAngleTo(image): int collidesWith(image): boolean -# Button.java +## Button.java Same as Image.java but can register touch. isPressed(): boolean -# Music.java +## Music.java Basic functions: play() pause() stop() delete() -# Sound.java +## Sound.java Basic functions: play() stop() delete() -# Device.java +## Device.java + get_screen_width(): int + get_screen_height(): int + setSavingInt(String, int) <- for saving numbers onto the device From aa2ca80d53dfd87870e8c4328c621c73f87712c8 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Mon, 14 May 2018 20:21:50 +0200 Subject: [PATCH 42/46] improved codestyle improved format improved isInScreen() improved comments added getAngleTo() warning --- engine/framework/Image.java | 60 ++++++++++++++----------------------- 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/engine/framework/Image.java b/engine/framework/Image.java index 4d9f7bc..6bf1b11 100644 --- a/engine/framework/Image.java +++ b/engine/framework/Image.java @@ -5,8 +5,8 @@ import android.graphics.Matrix; import android.graphics.Paint; -import ofenbach.exampleapp.main.Device; -import ofenbach.exampleapp.main.MainActivity; +import ofenbach.exampleapp.main.Device; // change this to your package name +import ofenbach.exampleapp.main.MainActivity; // change this to your package name import ofenbach.exampleapp.main.MainView; // change this to your package name /* able to display .png pictures*/ @@ -22,7 +22,7 @@ public class Image { - // File + // file Bitmap bitmap; int path; @@ -34,66 +34,63 @@ public class Image { Matrix m; Paint p; - // Gravity + // gravity public double gravity_factor, gravity_timer; - /* CONSTRUCTOR */ public Image(int path) { - this.path = path; + this.path = path; // save path - m = new Matrix(); + m = new Matrix(); // initialize everything p = new Paint(); - // Bitmap Creation + // bitmap creation BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false; bitmap = BitmapFactory.decodeResource(MainActivity.context.getResources(), path, options); } - /* DRAW */ public void draw() { - // Anglesettings + // angle & position settings m.reset(); m.postRotate(angle, bitmap.getWidth() / 2, bitmap.getHeight() / 2); m.postTranslate((float) (x/1920)*Device.get_screen_width(), (float) (y/1080)*Device.get_screen_height()); - // Gravity + // apply gravity if (gravity_factor != 0) { this.applyGravity(); } - // Draw + // draw MainView.global_canvas.drawBitmap(bitmap, m, p); } - /* SCALING */ public void scale() { - // Calculation + // calculation double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); double real_width = Device.get_screen_width() * ((double) bitmap.getWidth() / 480); double real_height = real_width * ratio;; - // Scaling + // scaling bitmap = Bitmap.createScaledBitmap(bitmap, (int) real_width, (int) real_height, false); } public void scale(double factor) { - // Calculation + // calculation double relative_width = 1080 / (factor * bitmap.getWidth()); double ratio = (double) bitmap.getHeight() / (double) bitmap.getWidth(); double width = Device.get_screen_width() / relative_width; double height = ratio * width; - // Scaling + // scaling bitmap = Bitmap.createScaledBitmap(bitmap, (int) width, (int) height, false); } @@ -101,22 +98,21 @@ public void scaleFullscreen() { bitmap = Bitmap.createScaledBitmap(bitmap, Device.get_screen_width(), Device.get_screen_height(), false); } - /* SET FUNCTIONS */ public void setAlpha(int alpha) { p.setAlpha(alpha); } public void setTransparency(double percent) { - int real_value = (int) percent * 255; + int real_value = (int) percent * 255; // conversion from percent to 0-255 p.setAlpha(real_value); } public void move(double distance) { - // Calculation + // calculation double distanceX = distance * Math.sin(angle); double distanceY = distance * Math.cos(angle); - // Update X Y + // update x y x += distanceX; y += distanceY; @@ -129,14 +125,14 @@ public void setX(double xPos) { this.x = xPos; } public void setXtoMiddle() { - //this.x = Device.get_screen_width() / 2 - this.getWidth() / 2; // old way + // old way: this.x = Device.get_screen_width() / 2 - this.getWidth() / 2; x = 1920 / 2 - getWidth() / 2; } public void setY(double yPos) { this.y = yPos; } public void setYtoMiddle() { - //this.y = Device.get_screen_height() / 2 - this.getHeight() / 2; // old way: relative but still absolut + //old way: this.y = Device.get_screen_height() / 2 - this.getHeight() / 2; y = 1080 / 2 - getHeight() / 2; // new way: relative/automatic } public void setAngle(double angle) { @@ -146,7 +142,6 @@ public void setAngle(double angle) { m.postTranslate((int) x, (int) y); } - /* GET FUNCTIONS */ public double getX() { return x; @@ -165,6 +160,8 @@ public int getAngle() { } public double getAngleTo(Image image) { + /* outdated, works but not recommended to use. */ + // Vars double delta_x; double delta_y; @@ -207,26 +204,15 @@ public Bitmap getBitmap() { return bitmap; } public boolean isInScreen() { - if (this.x > -this.getWidth() && this.x < Device.get_screen_width()) { - if (this.y > -this.getHeight() && this.y < Device.get_screen_height()) { - return true; - } else { - return false; - } - } else { - return false; - } + return (this.x > -this.getWidth() && this.x < Device.get_screen_width() && this.y > -this.getHeight() && this.y < Device.get_screen_height()); } - /* COLLISION */ public boolean collidesWith(Image image) { // See CollisionDetection.java return CollisionDetection.isCollisionDetected(bitmap, (int) x, (int) y, image.bitmap, (int) image.x, (int) image.y); - } - /* GRAVITY */ public void setGravity(double factor) { // e.g. factor=9.81, factor = 0 -> false, factor != 0 -> true this.gravity_factor = factor; @@ -241,12 +227,10 @@ public void increaseGravity(int increase) { public void setGravityTimer(int value) { this.gravity_timer = value; } - /* DELETE */ public void delete() { bitmap.recycle(); } - } From 8f900d6ad66ea23ae98975555725e615fe5fb487 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Wed, 16 May 2018 09:36:41 +0200 Subject: [PATCH 43/46] removed #enums --- CODESTYLE.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/CODESTYLE.md b/CODESTYLE.md index 5b31efa..9a7348e 100644 --- a/CODESTYLE.md +++ b/CODESTYLE.md @@ -60,6 +60,3 @@ boolean isXGreaterThan5 (int x) { return x > 5; } ``` - -## Enums -* Use enum class, not regular enums! From a2a38b1cc0addf8b0138b8e99cad66b509b88c47 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Wed, 16 May 2018 10:42:34 +0200 Subject: [PATCH 44/46] removed #proversion --- README.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/README.md b/README.md index 6a760d1..3746d43 100644 --- a/README.md +++ b/README.md @@ -39,13 +39,5 @@ If you feel like supporting my work, feel free to donate: Thank you! ❤️ -# pro version (NOT AVAILABLE ATM) 🏎️ -Another way to support me, is to buy the pro version for 5$ -+ no watermark 🚱 -+ active development 🖥️ -+ sprite support 🖼️ -+ save support 💾 -+ complete engine documentation 📚 - # contact ✉️ Questions? Email me: tim@ofenba.ch From a8d3d0fe268e9f90c382308d871455b18b29f5ff Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Sat, 19 May 2018 16:27:50 +0200 Subject: [PATCH 45/46] improved details improved #new features improved #example improved #planned features --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3746d43..1cb4d67 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,17 @@ # catengine developer edition 😼 Welcome to the developer-branch! From here you can check out some of the new features that aren't available yet. -It is not recommenced to use this version in your release apps, as there will be bugs. See full changelog: engine/main/MainActivity.java # new features 💪 -The update is done! I am working on bugfixes, stabilization etc. for the release. +The update is done! Release coming soon. + gravity support ✅ + save support ✅ + sprite support ✅ -+ automatic positions (resolution independent) ✅ ++ automatic positions ✅ + better touch functions ✅ -+ improved github doc ✅ ++ improved codestyle ✅ # guide 📖 1. Download the engine folder. @@ -22,9 +21,10 @@ The update is done! I am working on bugfixes, stabilization etc. for the release 6. Your app now runs catengine developer edition! # example 👀 -The new example has all the features that are available! +The example contains all new features that are available! # planned features 🤔 +Here's a list of features that will be implemented one day: + GUI version 😍 + simple drag&drop to create apps 🖱️ + simple kid-friendly coding 👶 From 9e6a71f099ae6c5f1f417b35f14aa9a6e4f685a6 Mon Sep 17 00:00:00 2001 From: "Tim B. Ofenbach" Date: Sat, 21 Jul 2018 00:07:42 +0200 Subject: [PATCH 46/46] better format --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1cb4d67..68ef5ec 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,12 @@ See full changelog: engine/main/MainActivity.java # new features 💪 The update is done! Release coming soon. -+ gravity support ✅ -+ save support ✅ -+ sprite support ✅ -+ automatic positions ✅ -+ better touch functions ✅ -+ improved codestyle ✅ ++ ✅ gravity support ++ ✅ save support ++ ✅ sprite support ++ ✅ automatic positions ++ ✅ better touch functions ++ ✅ improved codestyle # guide 📖 1. Download the engine folder.