@charset "UTF-8";
.markdown-body { line-height: 1.75; font-weight: 400; font-size: 15px; overflow-x: hidden; color: rgba(43, 43, 43, 1); font-family: -apple-system, system-ui, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; background-image: linear-gradient(90deg, rgba(159, 219, 252, 0.15) 3%, rgba(0, 0, 0, 0) 0), linear-gradient(1turn, rgba(159, 219, 252, 0.15) 3%, rgba(0, 0, 0, 0) 0); background-size: 20px 20px; background-position: center }
.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6 { padding: 30px 0; margin-top: 35px; margin-bottom: 10px; color: rgba(77, 208, 225, 1) }
.markdown-body h1 { font-size: 30px; text-align: center; position: relative; width: max-content; margin: 0 auto }
.markdown-body h1:before { position: absolute; content: ""; z-index: -1; top: -20px; height: 100%; width: 100px; left: 0; right: 0; margin: 0 auto; background: url("data:image/png;base64,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") center / 64px 64px no-repeat; opacity: 0.84 }
.markdown-body h1:after { position: absolute; content: ""; width: 150%; left: -25%; height: 50%; bottom: 12px; border-radius: 50%; background: linear-gradient(rgba(0, 0, 0, 0) 80%, rgba(77, 208, 225, 0.8)); opacity: 0.6; animation: 6s linear infinite h1animate }
@keyframes h1Animate { 0% { background-position: right bottom } 50% { background-position: right } 100% { background-position: right bottom } }
.markdown-body h2 { display: block; border-bottom: 4px solid rgba(77, 208, 225, 1); position: relative; font-size: 24px; padding: 12px 32px; margin: 30px 0 }
.markdown-body h2:before { width: 24px; height: 24px; left: 0; top: 0; margin: auto; background-size: 24px 24px; background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADGklEQVRYR81X32vTYBQ999s6mFjQgQ+DrbHiVFZYU4cDcQ/6pGhTFVYFEXGi82H+Bz448UnEF1Fx9ccEEcXpZE3d5tP2ooKiTacTHaLNpigMHDgnU9tcSbrWrkwWR0sbyEOSe885ObnfvV8IRT6oyPwoLQHBx+OVM5WJvSyEVAhnBOjt7yU/+/rr6r6l8TMO+F/EN0JQhICqQpD/xaRpcpAc9tS+M+9lBCia/oqBamK+zeDuQogQZaKJk3wcQjxSva7tGQGB2Ke1zIk3DNyMyNL+QpCnMQOaPsDAVuGAp9cjvbYc8Ec/bCYSg0zoiHilk1tHxqsqEsYlML4kjIpT/eurJxRNPweQU5VdrWaOEo1fgKAVbBgXIz73kF3R/ph+ghgdzMYWM29eAWlBJqgZaFlFYtC6nhWpaDqnSGlIlV1WjJ3DloDNgyNLncudqgX//Ucg3LxuStHGuhi8pqKCW3rqV342rwFjRznKm+/LNaN2yC237ThgF2wxcfMLeP6+ncrKzoPoKTGeLQbYbg4TNoC5iZPJY5HGVRdSNZAWYBclD3FzBQzrR8hACAKdzBzKA/4/IYioDQaOskBbpEG6PO8qKKSAEi3CnEb0Pw4oMf0OmKbTDWqh3Lw6EIiNBZi5lxh3wz4puBD5ovqAMvxhHSdFKxE1CQe3m/07TeTX4lcJdAhE+1Sv65Z5P/ByvIGTRowIZ9igbtXnmrOsbTvgj+kHBNMuBu9OdVw8EeU4nC1A0cYmAHZOTRrLhra4Z8ywnSN6vZHAFTA2WnnMfQB3qz73ddsOZM8CACFDIPSgQXqebXEgqgeZcAeEe6pXasm1f8ew3igMtAHWac0Uc/jYdyAaP0xEBwFsmgUPqbJ0NE2UKj4EGcahiOzuyhagaHpnmtgcVgTcCMuua7YdyAHbA3ArQNscVFbb4635aD6fnYaTvxxi9UNP7ddMXaRWVBdAcaLk6bDXPZCNZ9uBXEsDUX1T2Cc9yjig6Z0EHg3LK8/aqf6MwJKchkXfks1+0+JtSq3qLPa23BRR1B+T/6nkfMaW1r9hPt/MLtYfTLEpP+T9FNoAAAAASUVORK5CYII=") }
.markdown-body h2:after, .markdown-body h2:before { content: ""; display: block; position: absolute; bottom: 0 }
.markdown-body h2:after { right: 0; width: 400px; height: 10px; border-top-right-radius: 24px; background: linear-gradient(90deg, rgba(255, 255, 255, 1), rgba(77, 208, 225, 1)); max-width: 50vw }
.markdown-body h3 { margin: 30px 0; font-size: 18px; position: relative; padding: 4px 32px; width: max-content }
.markdown-body h3:before { border-bottom: 2px solid rgba(77, 208, 225, 1); width: 100%; content: ""; display: block; height: 28px; position: absolute; left: 0; top: 0; bottom: -2px; margin: auto; background-size: 28px 28px; background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABRklEQVRYR2NkGGDAOMD2M4w6YDQERkNg+ITAppcfY/8zMv3wF+NdTUrZQpUQ2PT6cz8Dw/8CkMWMDIwNvqK8jcQ6gmIHNN19EaXPx1XPyMCghrCUKcpPlGc5MY6gyAE+Fx52MjL8j3cU5a1UYWXtZGBkEAVb+p8hxU+Mby5NHQCxnKEMaskzJ37uFmUetkmMjAzrfUX4woixHBJlZAA0y2EmPPYU4enLkhGeQIqRJDsAh+UgO7duNpD3IcVykkOA2paT5ABaWE60A2hlOdEO8D3/4CMDIyMfWvySFefoaYSoROh74eFXBgYGLiTNVLGc+BC48PAnAwMDG9QBVLOcaAd8P5ox+x/jf5AjGLgYfnwnKqv9/8/PwPO/kFF/MSj0cAKiouD/0bgYoixFU8RovWgJIX1EOYCQIZTIjzpgNARGQ2DAQwAAvHBaIdB7zxsAAAAASUVORK5CYII="); background-repeat: no-repeat; animation: 2s infinite alternate h3animationbefore }
@keyframes h3AnimationBefore { 0% { width: 28px } 25% { width: 100% } 50% { width: 100% } 100% { width: 100% } }
.markdown-body h3:after { content: ""; display: block; width: 28px; height: 28px; position: absolute; border: 2px solid rgba(77, 208, 225, 1); border-radius: 50%; right: -15px; top: 0; bottom: 0; margin: auto; background-size: 28px 28px; background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABRklEQVRYR2NkGGDAOMD2M4w6YDQERkNg+ITAppcfY/8zMv3wF+NdTUrZQpUQ2PT6cz8Dw/8CkMWMDIwNvqK8jcQ6gmIHNN19EaXPx1XPyMCghrCUKcpPlGc5MY6gyAE+Fx52MjL8j3cU5a1UYWXtZGBkEAVb+p8hxU+Mby5NHQCxnKEMaskzJ37uFmUetkmMjAzrfUX4woixHBJlZAA0y2EmPPYU4enLkhGeQIqRJDsAh+UgO7duNpD3IcVykkOA2paT5ABaWE60A2hlOdEO8D3/4CMDIyMfWvySFefoaYSoROh74eFXBgYGLiTNVLGc+BC48PAnAwMDG9QBVLOcaAd8P5ox+x/jf5AjGLgYfnwnKqv9/8/PwPO/kFF/MSj0cAKiouD/0bgYoixFU8RovWgJIX1EOYCQIZTIjzpgNARGQ2DAQwAAvHBaIdB7zxsAAAAASUVORK5CYII="); animation: 2s infinite alternate h3animationafter }
@keyframes h3AnimationAfter { 0% { } 10% { } 50% { transform: rotate(-1turn) } 100% { transform: rotate(-1turn) } }
.markdown-body h4 { font-size: 16px }
.markdown-body h5 { font-size: 15px }
.markdown-body h6 { margin-top: 5px }
.markdown-body p { line-height: inherit; margin: 22px 0; letter-spacing: 2px; font-size: 14px; word-spacing: 2px }
.markdown-body img { max-width: 80%; border-radius: 6px; display: block; margin: 20px auto !important; object-fit: contain; box-shadow: 0 0 16px rgba(110, 110, 110, 0.45) }
.markdown-body figcaption { display: block; font-size: 13px; color: rgba(43, 43, 43, 1) }
.markdown-body figcaption:before { content: ""; background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAAGFBMVEVHcExAuPtAuPpAuPtAuPpAuPtAvPxAuPokzOX5AAAAB3RSTlMAkDLqNegkoiUM7wAAAGBJREFUKM9jYBhcgMkBTUDVBE1BeDGqEtXychNUBeXlKEqACsrLQxB8lnCQQClCiWt5OYoSiAIkJVAF5eVBqAqAShTAAs7l5ShKWMwRAmAlSArASpAVgJUkCqIAscESHwCVVjMBK9JnbQAAAABJRU5ErkJggg=="); display: inline-block; width: 18px; height: 18px; background-size: 18px; background-repeat: no-repeat; background-position: center; margin-right: 5px; margin-bottom: -5px }
.markdown-body hr { border-top: 1px solid rgba(77, 208, 225, 1); border-right: none; border-bottom: none; border-left: none; margin-top: 32px; margin-bottom: 32px }
.markdown-body del { color: rgba(77, 208, 225, 1) }
.markdown-body code { border-radius: 2px; overflow-x: auto; background-color: rgba(77, 208, 225, 0.08); color: rgba(38, 198, 218, 1); padding: 0.195em 0.4em }
.markdown-body pre { font-family: Menlo, Monaco, Consolas, Courier New, monospace; overflow: auto; position: relative; line-height: 1.75; box-shadow: 0 0 8px rgba(110, 110, 110, 0.45); border-radius: 4px; margin: 16px }
.markdown-body pre:before { content: ""; display: block; height: 30px; width: 100%; margin-bottom: -7px; background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAdCAYAAABcz8ldAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAhgSURBVGhD7Zp7bBTHHcdn33t7vvOdzy+ITVKDU0xIKG2ABCPTRCCaUiEVKWoqRJuASAhCitRCVKSoalFUKZBiSmmFRRJKRUnUtIpo+aNqGgwoOCmuFUIRzxjwE4zte+97drYzztji8HPvtkit/PnH+n1397Tz+83vN/PbMZhmmmmm+d+BoX8n5diihcGqgFQf5vk6BMAskWUlw3GyFnIvtqWSf91w7mKC3npfOLX7wYeiIa6BBWCOLLFRF2NB0JvIOP/80YG+k2ev6S699b/OzOfKBW5l5KsgyC4DCFQDnpEAdE1goc/dlNPc/Up7P711UiYNSMuyxeUzZPnHgGHWh5XADEkSAcdiN+AnEXIBhBComgFU0/xQR+jnj51sOUMf9Z0NKyL8S9+JPBEN8zuCMrsqGOA5QWAAyzLAxe53HBeYFgJp1c5Cx33nyIfpV3e+22/Sx32nev/sMCgVnmM4bjOniAtZWQAsz315EfsGQQc4hgWcjHkCmOj1rheuNn95cXwmDMiVp5etC/D8m5FwUWVQUYYGPh6mZYFUOgsGVa1pXvOZzVT2jRuH54RM230jEuI3RcIiL4l4UkxAJmuD/riVsqD7ct2m9nep7BtVTbVfZ0uE/UIk+CQflAHDjf8+Lg6MldYATGpH3c/Ul7p3dWXppVGM6eElJSHmnQWPbSlRlN1lJcUBjqNRnwJZVQO3B5P/uq5rK1d90pakckFcaKp5UJHY92JR8YlwkUDVySEZfGfQdO7E7Z8s2HL9TSoXTPXRud9nA8IBqSwcZgWeqpPj6BYw7yTbXBN9q2v9lQEq5zBmWA8vWLCptCi4tzwW8RQMQlFQATPLSh6vCSh/plJBkMyQBHZfWYnkKRgEktEVpTJXERN2Xzo4ex2VC6K6qXYpF5b3ypVRT8EgcAERSJXRbwCBOTFzXblM5RxGBaRt+ZPYA+LO0mgxz5K1Ig+UgAzKIuGnz39z6S+olDeaibaXRsU1RUFvgx+GwTWgPCaDgMw2XXpr9gwq50XV0bkxJiYeEiNF5cwE5XsiOEkAUkXkUW51SSOVchjl8WKef604XFSRbzCGCYeCoESStv/p8QU1VPIM3knNDynctnBRfsEYhgSlNCIGgQv2UCkvGIHZgteMh1nBW9W4F16RAM6yDVV7amZTaYQcr59cuuhhWRTWBvAMLxQGeyFSHOLnh0MvUskz5RF+fbRYDEy0mZgqQYUHOLhr//b6rGoqeaLqQG0pw3PrBbyA+4EQUkRmhvgqNUfICUipKK4OKUqIJVPKB0jpEhjmWWp64jdbKmVZZNYogcJm493gsifOqhDyeh9GYR/FM7sW+DA5CKR0MSK3tvKZkpwB5gRE4tjFEr7RL0iWBGV51vHFCyupNGWWPqLgnoer9mtyEGSJAzwLllDTGzyznDjRN/CwOFkoFb4bm0eVIXICgpvdGoEvrF7fC89zfLkkeV5HbOhWiTwTpKYvCAJLGshRdXtKMKAWlyxq+MPQLk1h66g5RE5ABJYNFrqY3wvJklJRUKg5ZWLFXIA86yek2uDOPkBNb3CM5Pf7DL2QyIrUGiLH+xC5Bmmm/ARnHUhC6PnzxWDK0RH5HuIjZGy27erU9AZ0dTIWXyG+NpBBrSFySxZw220IqeUPFoS6jVAPNadM7yDsgNB1qOkLuAziMYIb1PQGA75wIaKGPyAb+9oF16g5RE5ALIQ+tSyLWoWDEAK6aXW3JlK9VJoyx1oyvVkNdvo5KXXDAVkdnaKmNwx0xjH98w3JNmTCm+Bc9hKVhsgJSI9pvp9Vdd++jmq6AXB2/HHrhcs5aTkVDv0DFzoHvKdq/mQsKX/4t7KJLDpOJW+IbAvMGoMkxfwAWZB8DT7W1diTE+WcgKz6pK1bs6z3daPwmJDsSKt6ZsCyjlLJMz0DsDGZ8SdlDROBjOb8YeWOjptU8kTXusuaazu7oJrfEnQvdkpVcUn6PTVHyAkIIW7br/Unklni0EJIZ1WgGsauZR+fvUglz6zY0dGfVp09ybRNlfwgi3k8YSbvJJ29VMoLt9v6rZVQL7hOYUubndHJGclBtzn1byqNMCogi09/2nFb01/oj+f/5TyjauBOKtPcZ1r7qZQ3f2lRfxZPWi2anp8TSDAGExZMa2jr8u03L1M5L7q3Xc+iAeuHRl/ScvPcjSLDBnZS/cjtNHd2v3171Ewbs9N5q7Pn4otVMx3btBsCsoRbk1FxG5dMVgMDqfTpXl1/tuFMa5zKefPROdX59qLQBwLnNog8Wy1OcjB1N+QEsW/QsFNZuO35Xb1v98QLX4/Sx+O3wqujrQ6013ABUWI8+AaqBjAH01+ghL22+5X2PirnMG7r+esbnae/V1neauvGSoHjigTcVU7UGFm2DeK4ttxKpQ+mLPvl+o/PjnkAkw9HTqSMmVHhyAMx9iFcSh/BHTfLceO/C8mKjApBf9zszGhoY92m9sN+BGOY9AeD7eGniv8OTaOB4dgyTsQd9wS+IQu4lciYdkI7CLrNH3Rvbb9FL41i0tbzVP2iWJkobpN5fmM4IJfJskTP1Bk8A9HQmbpmGDBrWqdVCN/Yd7PjxKGOXn+bmbto3feVVcVB9qehIL8EJy8nChwgr0O2xxBnhGU5eP2CfYbl/m4gBRsbtneMORP9oGpjpcCsiKzHHfdOPiQ/wMniyFEu2dbiTQCAeN/vavC466BGYLttXc9fmXBXMGlAhiHHur+sq6uPiUI9z7CVHMPwBnLSuuN8FuC48/Oaz1ylt94XfrW5ouyprwWfYRkwNyCyYYjwkBHows1fa+tV/fzGxlv39b9gqvfPmQ+i/HK8KlcBjhHwfl8HEHyOd1JnuzZd66S3TTPNNNP8/wDAfwDG7G0m9LKBpwAAAABJRU5ErkJggg==") 10px 10px / 40px no-repeat }
.markdown-body pre>code { font-size: 12px; padding: 15px 12px; margin: 0; word-break: normal; display: block; overflow-x: auto; color: rgba(51, 51, 51, 1); background: rgba(248, 248, 248, 1) }
.markdown-body a { color: rgba(77, 208, 225, 1); border-bottom: 1px solid rgba(77, 208, 225, 1); font-weight: 400; text-decoration: none; margin: 0 4px }
.markdown-body a:active, .markdown-body a:hover { background-color: rgba(77, 208, 225, 0.1) }
.markdown-body strong { color: rgba(38, 198, 218, 1) }
.markdown-body strong:before { content: "「" }
.markdown-body strong:after { content: "」" }
.markdown-body em { font-style: normal; color: rgba(77, 208, 225, 1); font-weight: 700 }
.markdown-body table { display: inline-block !important; font-size: 12px; width: auto; max-width: 100%; overflow: auto; border: 1px solid rgba(246, 246, 246, 1) }
.markdown-body thead { background: rgba(246, 246, 246, 1); color: rgba(0, 0, 0, 1); text-align: left }
.markdown-body tr:nth-child(2n) { background-color: rgba(77, 208, 225, 0.05) }
.markdown-body td, .markdown-body th { padding: 12px 7px; line-height: 24px }
.markdown-body td { min-width: 120px }
.markdown-body blockquote { margin: 2em 0; padding: 24px 32px; border-left: 4px solid rgba(38, 198, 218, 1); background: rgba(77, 208, 225, 0.15); position: relative }
.markdown-body blockquote:before { content: "❝"; top: 8px; left: 8px; color: rgba(77, 208, 225, 1); font-size: 30px; line-height: 1; font-weight: 700; position: absolute; opacity: 0.7 }
.markdown-body blockquote:after { content: "❞"; font-size: 30px; position: absolute; right: 8px; bottom: 0; color: rgba(77, 208, 225, 1); opacity: 0.7 }
.markdown-body blockquote p { color: rgba(89, 89, 89, 1); line-height: 2 }
.markdown-body ol, .markdown-body ul { color: rgba(89, 89, 89, 1); padding-left: 28px }
.markdown-body ol li, .markdown-body ul li { margin-bottom: 0; list-style: inherit }
.markdown-body ol li .task-list-item, .markdown-body ul li .task-list-item { list-style: none }
.markdown-body ol li .task-list-item ol, .markdown-body ol li .task-list-item ul, .markdown-body ul li .task-list-item ol, .markdown-body ul li .task-list-item ul { margin-top: 0 }
.markdown-body ol ol, .markdown-body ol ul, .markdown-body ul ol, .markdown-body ul ul { margin-top: 3px }
.markdown-body ol li { padding-left: 6px }
@media (max-width: 720px) { .markdown-body h1 { font-size: 24px } .markdown-body h2 { font-size: 20px } .markdown-body h3 { font-size: 18px } }.markdown-body pre, .markdown-body pre>code.hljs { background: rgba(255, 255, 255, 1); color: rgba(0, 0, 0, 1) }
.hljs-comment, .hljs-quote, .hljs-variable { color: rgba(0, 128, 0, 1) }
.hljs-built_in, .hljs-keyword, .hljs-name, .hljs-selector-tag, .hljs-tag { color: rgba(0, 0, 255, 1) }
.hljs-addition, .hljs-attribute, .hljs-literal, .hljs-section, .hljs-string, .hljs-template-tag, .hljs-template-variable, .hljs-title, .hljs-type { color: rgba(163, 21, 21, 1) }
.hljs-deletion, .hljs-meta, .hljs-selector-attr, .hljs-selector-pseudo { color: rgba(43, 145, 175, 1) }
.hljs-doctag { color: rgba(128, 128, 128, 1) }
.hljs-attr { color: rgba(255, 0, 0, 1) }
.hljs-bullet, .hljs-link, .hljs-symbol { color: rgba(0, 176, 232, 1) }
.hljs-emphasis { font-style: italic }
.hljs-strong { font-weight: 700 }

最近掌门人在写3D游戏,对于其中的物理效果很感兴趣,今天我将使用纯JavaScript来实现一个简易的物理模拟,其中包括碰撞检测与响应、摩擦力与空气阻力、以及物体的破坏效果。本文的目标是创建一个可以控制物体的环境,其中物体会按照物理定律移动,并且能够相互之间发生碰撞和反应。并且不会使用任何第三方库,从零实现。

碰撞检测

首先就是碰撞检测,在游戏中这是最基础的效果,下述栗子中将会实现检测两个矩形物体是否发生碰撞。

function isColliding(rect1, rect2) {
return (
rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.height + rect1.y > rect2.y
);
} // 测试碰撞检测
const rect1 = { x: 5, y: 5, width: 50, height: 50 };
const rect2 = { x: 20, y: 20, width: 50, height: 50 }; console.log(isColliding(rect1, rect2)); // 输出:true

碰撞响应

正常情况下,当两个物体发生碰撞时,我们需要计算它们的碰撞响应。在这里,就简单地反转它们的速度来模拟弹性碰撞。

function resolveCollision(obj1, obj2) {
const tempVelocity = obj1.velocity;
obj1.velocity = obj2.velocity;
obj2.velocity = tempVelocity;
} // 测试碰撞响应
let obj1 = { velocity: { x: 5, y: 0 } };
let obj2 = { velocity: { x: -3, y: 0 } }; if (isColliding(rect1, rect2)) {
resolveCollision(obj1, obj2);
} console.log(obj1.velocity, obj2.velocity); // 输出:{ x: -3, y: 0 } { x: 5, y: 0 }

3. 摩擦力

摩擦力会减缓物体在接触表面上的移动。在这个示例中,我们使用一个简单的摩擦系数来模拟摩擦力对速度的影响。

function applyFriction(velocity, friction) {
velocity.x *= friction;
velocity.y *= friction;
} // 测试摩擦力
let velocity = { x: 10, y: 0 };
const friction = 0.95; // 摩擦系数 applyFriction(velocity, friction); console.log(velocity); // 输出:{ x: 9.5, y: 0 }

空气阻力

空气阻力会减缓物体在空中的移动。我们可以通过减小速度的百分比来模拟这种效果.

function applyDrag(velocity, drag) {
velocity.x *= (1 - drag);
velocity.y *= (1 - drag);
} // 测试空气阻力
let velocity = { x: 10, y: 0 };
const drag = 0.05; // 空气阻力系数 applyDrag(velocity, drag); console.log(velocity); // 输出:{ x: 9.5, y: 0 }

物体破坏

首先当物体的速度超过一定阈值时,我们可以假设物体已经被破坏。这里我们定义一个简单的函数来判断物体是否应该被破坏,并在破坏发生时改变其状态。

function checkAndApplyDamage(obj, threshold) {
const speed = Math.sqrt(obj.velocity.x ** 2 + obj.velocity.y ** 2);
if (speed > threshold) {
obj.isDestroyed = true;
}
} // 测试物体破坏
let obj = { velocity: { x: 50, y: 0 }, isDestroyed: false };
const damageThreshold = 30; // 破坏阈值 checkAndApplyDamage(obj, damageThreshold); console.log(obj.isDestroyed); // 输出:true

完整案例

俗话说光说不练假把式,所有的都是为最终的效果服务的,最后我们将上述的所有效果整合起来,实现一个简单的demo效果。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>物理模拟</title>
<style>
canvas {
border: 1px solid black;
}
#controls {
margin-top: 10px;
}
.info {
margin-right: 10px;
}
</style>
</head>
</body>
<canvas id="simulation" width="500" height="300"></canvas>
<div id="controls">
<div class="info">
<label for="friction">摩擦力:</label>
<input type="range" id="friction" min="0" max="1" step="0.01" value="0.99">
<span id="frictionValue">0.99</span>
</div>
<div class="info">
<label for="drag">风阻:</label>
<input type="range" id="drag" min="0" max="0.1" step="0.001" value="0.01">
<span id="dragValue">0.01</span>
</div>
<div class="info">
<label for="threshold">临界值:</label>
<input type="range" id="threshold" min="0" max="500" step="1" value="25">
<span id="thresholdValue">25</span>
</div>
<button id="restartBtn">重启模拟</button>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
// 获取canvas和context
const canvas = document.getElementById('simulation');
const ctx = canvas.getContext('2d'); // 定义物体构造函数
function GameObject(x, y, width, height, velocity) {
this.initialX = x;
this.initialY = y;
this.width = width;
this.height = height;
this.initialVelocity = { ...velocity };
this.velocity = { ...velocity };
this.isDestroyed = false;
} // 添加方法到GameObject原型
GameObject.prototype = {
reset() {
this.x = this.initialX;
this.y = this.initialY;
this.velocity = { ...this.initialVelocity };
this.isDestroyed = false;
},
isColliding(other) {
return (
this.x < other.x + other.width &&
this.x + this.width > other.x &&
this.y < other.y + other.height &&
this.height + this.y > other.y
);
},
resolveCollision(other) {
if (!this.isDestroyed && !other.isDestroyed) {
console.log('打印碰撞前的速度:', Math.sqrt(this.velocity.x ** 2 + this.velocity.y ** 2), Math.sqrt(other.velocity.x ** 2 + other.velocity.y ** 2));
const tempVelocity = this.velocity;
this.velocity = other.velocity;
other.velocity = tempVelocity;
console.log('打印碰撞后的速度:', Math.sqrt(this.velocity.x ** 2 + this.velocity.y ** 2), Math.sqrt(other.velocity.x ** 2 + other.velocity.y ** 2));
}
},
update(friction, drag, threshold) {
if (this.isDestroyed) return; // 应用摩擦力和空气阻力
this.velocity.x *= friction;
this.velocity.y *= friction;
this.velocity.x *= (1 - drag);
this.velocity.y *= (1 - drag); // 更新位置
this.x += this.velocity.x;
this.y += this.velocity.y; // 检查破坏
const speed = Math.sqrt(this.velocity.x ** 2 + this.velocity.y ** 2);
if (speed > threshold) {
this.isDestroyed = true;
}
},
draw() {
ctx.fillStyle = this.isDestroyed ? 'red' : 'blue';
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}; // 实例化物体,确保设置了 x 和 y
const obj1 = new GameObject(100, 100, 50, 50, { x: 5, y: 0 });
const obj2 = new GameObject(300, 100, 50, 50, { x: -5, y: 0 }); // 设置物理参数
let friction = 0.99;
let drag = 0.01;
let destructionThreshold = 25; // 获取控件元素
const frictionInput = document.getElementById('friction');
const dragInput = document.getElementById('drag');
const thresholdInput = document.getElementById('threshold');
const frictionValueDisplay = document.getElementById('frictionValue');
const dragValueDisplay = document.getElementById('dragValue');
const thresholdValueDisplay = document.getElementById('thresholdValue');
const restartBtn = document.getElementById('restartBtn'); // 更新参数值的函数
function updateParameters() {
friction = parseFloat(frictionInput.value);
drag = parseFloat(dragInput.value);
destructionThreshold = parseFloat(thresholdInput.value);
} // 监听滑动条的变化
frictionInput.addEventListener('input', function () {
frictionValueDisplay.textContent = this.value;
});
dragInput.addEventListener('input', function () {
dragValueDisplay.textContent = this.value;
});
thresholdInput.addEventListener('input', function () {
thresholdValueDisplay.textContent = this.value;
}); // 动画循环函数
let animationFrameId; function animate() {
animationFrameId = requestAnimationFrame(animate); // 清除画布
ctx.clearRect(0, 0, canvas.width, canvas.height); // 更新和绘制物体
obj1.update(friction, drag, destructionThreshold);
obj2.update(friction, drag, destructionThreshold);
obj1.draw();
obj2.draw(); // 碰撞检测和响应
if (obj1.isColliding(obj2)) {
obj1.resolveCollision(obj2);
}
} // 启动动画
animate(); // 重新开始动画的函数
function restartAnimation() {
// 取消当前的动画帧请求
cancelAnimationFrame(animationFrameId); // 重置物体状态
obj1.reset();
obj2.reset(); // 更新参数
updateParameters(); // 重新开始动画
animate();
} // 绑定重启按钮事件
restartBtn.addEventListener('click', restartAnimation); })
</script>
<body>

总结

上述的案例我们实现了简单的物理模拟效果,只是给大家一个思路,毕竟万物皆可JS嘛,但是如果大家想要在项目中使用的话,就需要更加拟真和复杂的算法,本文只是带大家大概的了解一下它的实现方式。

大家快去试试吧,俗话说眼过千遍,不如手过一遍,说不定大家在实现的过程中,会找到更加方便简易的实现方法。

JavaScript 从零实现物理模拟的更多相关文章

  1. JavaScript : 零基础打造自己的类库

    写作不易,转载请注明出处,谢谢. 文章类别:Javascript基础(面向初学者) 前言 在之前的章节中,我们已经不依赖jQuery,单纯地用JavaScript封装了很多方法,这个时候,你一定会想, ...

  2. JavaScript: 零基础轻松学闭包

    本文面向初学者,大神轻喷. 闭包是什么? 初学javascript的人,都会接触到一个东西叫做闭包,听起来感觉很高大上的.网上也有各种五花八门的解释,其实我个人感觉,没必要用太理论化的观念来看待闭包. ...

  3. JavaScript : 零基础打造自己的jquery类库

    写作不易,转载请注明出处,谢谢. 文章类别:Javascript基础(面向初学者) 前言 在之前的章节中,我们已经不依赖jQuery,单纯地用JavaScript封装了很多方法,这个时候,你一定会想, ...

  4. JavaScript学习笔记之数值

    JavaScript内部,所有数字都是以64位浮点数形式储存,即使整数也是如此.(整数也是通过64浮点数的形式来存储的) 所以,1+1.0=2:且1===1.0的 浮点数不是精确的值,所以涉及小数的比 ...

  5. js正则:零宽断言

    JavaScript正则表达式零宽断言 var str="abnsdfZL1234nvcncZL123456kjlvjkl"var reg=/ZL(\d{4}|\d{6})(?!\ ...

  6. 浅析JavaScript正则表达式

    1.正则表达式的定义 正则表达式是一个描述字符模式的对象.JavaScript的RegExp类表示正则表达式,String和RegExp都定义了方法,后者使用正则表达式进行强大的模式匹配和文本检索与替 ...

  7. JavaScript String 字符串方法

    JavaScript String 字符串方法汇总   1.str.indexOf() 方法查找字符串中的字符串  返回   字符串中指定文本首次出现的索引(位置)       JavaScript ...

  8. 零基础学习Web前端开发

    目录 技术背景 开发环境 学习过程 参考资料 结束语 技术背景 什么是前端开发? 前端开发是创建Web页面或App等将界面呈现给用户的过程.通过使用 HTML,CSS,JavaScript,以及它们衍 ...

  9. ApacheCN JavaScript 译文集(二) 20211123 更新

    使用 Meteor 构建单页 Web 应用 零.前言 一.制作 Meteor 应用 二.构建 HTML 模板 三.存储数据和处理集合 四.控制数据流 五.使我们的应用与路由通用 六.保持会话状态 七. ...

  10. ApacheCN JavaScript 译文集 20211122 更新

    JavaScript 编程精解 中文第三版 零.前言 一.值,类型和运算符 二.程序结构 三.函数 四.数据结构:对象和数组 五.高阶函数 六.对象的秘密 七.项目:机器人 八.Bug 和错误 九.正 ...

随机推荐

  1. Chatbox接入硅基流动deepseek R1模型API

    Chatbox接入硅基流动deepseek R1模型API 注册硅基流动,填入邀请码会获得14元的免费额度 硅基流动最新邀请码:9MqV8tO4 注册硅基流动后 新建一个秘钥 回到模型广场,选择dee ...

  2. Python - [03] 基础语法

    题记部分 一.标识符 第一个字符必须是字母表中字母或下划线_ 标识符的其他部分由字母.数字和下划线组成 标识符对大小写敏感 二.Python保留字 三.注释 (1)单行注释:以#开头 #!/usr/b ...

  3. Chrome打开知乎报ERR_HTTP2_PROTOCOL_ERROR错误的问题

    打开 chrome://flags/ 页面 找到 Block insecure private network requests. 和 Enable Trust Tokens 两项 将其值从 Defa ...

  4. 机器学习 | 强化学习(1) | 马尔科夫决策过程(MDP)概论

    最近在搞强化学习(Reinforcement Learning),打算把之前写的笔记整理一下 本文基于大卫 希尔维(David Silver)教授的强化学习概论课程,视频中所采用的样例学生马尔科夫链( ...

  5. burpsuite激活

    激活burpsuite--教程 点击Start 文件,把三个框都选上 点击RUN,会自动启动,复制一下那个证书 粘贴刚刚复制的密钥,点击下一个即可 这里点击手动激活,复制请求,粘贴到刚刚那个激活程序的 ...

  6. python sqlmap 检测sql注入点及php网站sql注入防护运维操作实例

    问题描述:使用python sqlmap 检测存在sql注入风险,网站为php语言 操作步骤:1.本地电脑系统是win 7,查看未安装python,需要先安装python,注:win 7安装pytho ...

  7. 学习理论:单阶段代理损失的(H, R) - 一致界证明

    1 导引 我们在上一篇博客<学习理论:预测器-拒绝器多分类弃权学习>中介绍了弃权学习的基本概念和方法,其中包括了下列针对多分类问题的单阶段预测器-拒绝器弃权损失\(L_{\text{abs ...

  8. 震惊!C++程序真的从main开始吗?99%的程序员都答错了

    嘿,朋友们好啊!我是小康.今天咱们来聊一个看似简单,但实际上99%的C++程序员都答错的问题:C++程序真的是从main函数开始执行的吗? 如果你毫不犹豫地回答"是",那恭喜你,你 ...

  9. RSA算法详解及相关数学原理解析

    RSA算法详解及相关数学原理解析 前言 ‍ 为了记录自己学习密码学的过程,也是为了便于个人应付相关课程的考核,故写此博客. 本博客总结了怎么用C++手搓一个RSA算法,以及补补欠缺的一些数学知识和可能 ...

  10. kubeadm init 或 join 失败 [kubelet-check] Initial timeout of 40s passed.

    前言 kubeadm 初始化或 join 时,报错: [etcd] Creating static Pod manifest for local etcd in "/etc/kubernet ...